package jatek0003;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Random;

import javax.swing.JComboBox;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import jatek.Jatek;

import jxl.Workbook;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;

public class Jatek0003  implements Jatek,ActionListener {

	private static int tableWidth=500;
	
	private Jatek0003GameData jgd = new Jatek0003GameData();
	private Jatek0003Panel jk0003 = new Jatek0003Panel();
	
	public Jatek0003(){
		jk0003.getIndifferent().addActionListener(this);
		jk0003.getA1().addActionListener(this);
		jk0003.getA2().addActionListener(this);

		jk0003.getSex().setActionCommand("sex");
		jk0003.getSex().addActionListener(this);
		jk0003.getAge().setActionCommand("age");
		jk0003.getAge().addActionListener(this);
	}
	
	@Override
	public void closeGame() {
		jk0003.getGameResults().setText("Számított eredmények");
		jk0003.getGameInputContent().setText("");
		jgd.getAns().clear();
		jgd.setRandomNums(null);
		jgd.setClicked(null);
		jgd.setSaved(false);
		jgd.setToExcel(false);
		jk0003.setPanel("input");
		jk0003.getA1().setEnabled(false);
		jk0003.getA2().setEnabled(false);
		jk0003.getIndifferent().setEnabled(false);
		

	}

	@Override
	public boolean createSaveDataFormat(File save) {
		if(!jgd.isToExcel()){
			jk0003.showMessage("toExcelProblem");
			return false;
		}
		try {
			WritableWorkbook w= Workbook.createWorkbook(save);		
			WritableSheet s = w.createSheet("Adatok", 0); 
			
			s.addCell(new Label(0, 0, "Információk a játékról"));
			s.addCell(new Label(0, 3, "Kód"));s.addCell(new Label(1, 3, jgd.getCode()));
			s.addCell(new Label(0, 5, "Név"));s.addCell(new Label(1, 5, jgd.getName()));
			s.addCell(new Label(0, 7, "Szerző"));s.addCell(new Label(1, 7, jgd.getAuthor()));
			s.addCell(new Label(0, 9, "Dátum"));s.addCell(new Label(1, 9, jgd.getDate()));
			
			s.addCell(new Label(0, 14, "E1"));
			s.addCell(new Label(1, 14, "E2"));
			s.addCell(new Label(2, 14, "A1"));
			s.addCell(new Label(3, 14, "A2"));
			s.addCell(new Label(4, 14, "A1 - data"));
			s.addCell(new Label(5, 14, "A2 - data"));
			s.addCell(new Label(6, 14, "Választás"));
			s.addCell(new Label(7, 14, "életkor"));
			s.addCell(new Label(8, 14, "nem"));
			
			int rowNum=15;
			
			for(int i =0;i<jgd.getAns().size();i++){
				s.addCell(new Label(0, rowNum, jgd.getE1()));
				s.addCell(new Label(1, rowNum, jgd.getE2()));
				s.addCell(new Label(2, rowNum, jgd.getA1()));
				s.addCell(new Label(3, rowNum, jgd.getA2()));
				
				s.addCell(new Number(4, rowNum, jgd.getAns().get(i).getAn1()));
				s.addCell(new Number(5, rowNum, jgd.getAns().get(i).getAn1()));
				
				s.addCell(new Label(6, rowNum, jgd.getAns().get(i).getAn2()));
				s.addCell(new Number(7, rowNum,jgd.getActAge()));
				s.addCell(new Label(8, rowNum, jgd.getActSex()));
				rowNum++;
			}
			DecimalFormat df = new DecimalFormat("###.########");
			if(jgd.getAlfa()>=0){
				s.addCell(new Label(1, rowNum+3, "Az Ön alfa-pesszimizmus értéke: "+df.format(jgd.getAlfa())));
				
			}else{
				s.addCell(new Label(1, rowNum+3, "Az Ön alfa-pesszimizmus értéke: Válaszai alapján nem meghatározható."));
			}
			
			w.write();
			w.close();			
		} catch (WriteException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} 
		return true;
	}
	/**
	 * Adatokat küldünk egy .php fájlnak, és vizsgáljuk, hogy sikeres
	 * volt-e a művelet, azaz a .php azt a kimenetet produkálta-e, mint
	 * amit vártunk.
	 * @return Boolean Sikeres-e az adatbevitel.
	 */
	public boolean sendDataToPhp(){
		SimpleDateFormat timestampFormatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
		Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
		String timestampStr=timestampFormatter.format(currentTimestamp).toString();
		
		for(int i =0;i<jgd.getAns().size();i++){
			  boolean val=false;
			  String resultsAsString = "E1=" + jgd.getE1() + "&E2=" + jgd.getE2()+ "&A1=" + jgd.getA1()+ "&A2=" + jgd.getA2()+ "&A1v=" + jgd.getAns().get(i).getAn1()+ "&A2v=" + jgd.getAns().get(i).getAn1()+ "&choice=" + jgd.getAns().get(i).getAn2()+ "&age=" + jgd.getActAge()+ "&sex=" + jgd.getActSex()+ "&timestamp=" + timestampStr;
			  byte[] resultsAsBytes = resultsAsString.getBytes(); 
			  URL url = jgd.getCodeBase();
			  try {
				url = new URL(url + jgd.getPhpName());
				//url = new URL(url + "dataToDb.php");
				//System.out.println(url.toString());
				URLConnection con = url.openConnection();   
		        ((HttpURLConnection) con).setRequestMethod("POST");  
		        con.setDoOutput(true);  
		        con.setDoInput(true);  
		        con.setUseCaches(false);  
		   
		        OutputStream out = con.getOutputStream();   
		        out.write(resultsAsBytes);   
		        out.flush();   
		        
		        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));  
		        String line = in.readLine();  
		        while(line != null){  
		        	//System.out.println(line);
		            if(line.contains("success"))  {
		                val = true;  
		            }
		            if(line.equals("")) {
		            	break;
		            }  
		            line = in.readLine();  
		        }  
		   
		        in.close();   
		        out.close();   
		            
			} catch (MalformedURLException e) {
				jk0003.showMessage("mysqlError");
				//System.out.println(e.getMessage());
	        	return false;

			} catch (IOException e) {
				jk0003.showMessage("mysqlError");
				//System.out.println(e.getMessage());
	        	return false;
				
			}catch (Exception e) {
				jk0003.showMessage("mysqlError");
				//System.out.println(e.getMessage());
	        	return false;
				
			}
	        if(!val){
	        	  //System.out.println("itt nem jó");
	        	  jk0003.showMessage("mysqlError");
	        	  return false;
	        }
        }
		return true;
	}
	@Override
	public void loadData(Document d){
		Element root = d.getDocumentElement();
		Element gameElement=null;
		NodeList children=null;
		
		children = root.getElementsByTagName("input");
		gameElement = (Element)children.item(0);
		jgd.setOrder(gameElement.getAttribute("order"));
		
		getLabel(root,gameElement,children,"information");
		getLabel(root,gameElement,children,"name");
		getLabel(root,gameElement,children,"description");
		getLabel(root,gameElement,children,"date");
		getLabel(root,gameElement,children,"E1");
		getLabel(root,gameElement,children,"E2");
		getLabel(root,gameElement,children,"A1");
		getLabel(root,gameElement,children,"A2");
		getLabel(root,gameElement,children,"step");
		
		//author
		String author="";
		children = root.getElementsByTagName("author");
		for (int childrenNum = 0; childrenNum < children.getLength(); childrenNum++){
			gameElement = (Element)children.item(childrenNum);
			author+=gameElement.getFirstChild().getNodeValue()+"<br>";
        }
	
		jk0003.getA1().setText(jgd.getA1());
		jk0003.getA2().setText(jgd.getA2());
		jgd.setActRound(0);
		jgd.setAuthor(author);
		jgd.setRounds((int) ((int)1/jgd.getStep()));
		if("random".equals(jgd.getOrder())){
			double[] newRnd=new double[jgd.getRounds()+1];
			for(int i = 0; i<=jgd.getRounds();i++){
				newRnd[i]=(jgd.getStep()*(double)i);
			}
			jgd.setRandomNums(newRnd);
		}
		jgd.setGameInputHtmlContent("<html>"+createGameContent(jgd.getOrder(),jgd.getActRound())+"</html>");
		jk0003.showMessage("loaded");
	}
	/**
	 * Az xml egy magadott tagjének tartalmát kérdezi le, és tárolja. 
	 * Egyelemű tagekre vonatkozik.
	 * @param root Element
	 * @param gameElement Element
	 * @param children NodeList
	 * @param elementName String
	 */
	private void getLabel(Element root,Element gameElement,NodeList children,String elementName){
		children = root.getElementsByTagName(elementName);
		gameElement = (Element)children.item(0);
		if(elementName.equals("information")) jgd.setCode(gameElement.getAttribute("code"));
	      else if(elementName.equals("name")) jgd.setName(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("description"))jgd.setDescription(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("date")) jgd.setDate(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("E1")) jgd.setE1(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("E2")) jgd.setE2(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("A1")) jgd.setA1(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("A2")) jgd.setA2(gameElement.getFirstChild().getNodeValue());
	      else if(elementName.equals("step")) jgd.setStep(Double.parseDouble(gameElement.getFirstChild().getNodeValue()));
	}
	
	/**
	 * Az aktuális feladatot írja ki a felhasználónak. Illetve,
	 * ha minden kérdésre megkaptuk a választ, jelzi, hogy a tesztnek vége,
	 * és meghívja a sendDataToPhp() metódust is.
	 * 
	 * @param order String lejátszás sorrendje up|down|random
	 * @param round int aktuális kör a játékon belül
	 * @return String az új inputtal tér vissza, amire a tesztalany reagál
	 */
	private String createGameContent(String order,int round){
		DecimalFormat df = new DecimalFormat("###.########");
		
		if(round>jgd.getRounds() && !jgd.isSaved()){
			jk0003.getA1().setEnabled(false);
			jk0003.getA2().setEnabled(false);
			jk0003.getIndifferent().setEnabled(false);
			Collections.sort(jgd.getAns(),new Answer());
			String answers="<html><p>Az Ön által adott válaszok</p><hr><table border=1 width="+tableWidth+">";
			for(int i = 0;i<jgd.getAns().size();i++){
				answers+="<tr><td>"+df.format(jgd.getAns().get(i).getAn1())+"</td><td>"+jgd.getAns().get(i).getAn2()+"</tr>";
			}
			answers+="</table>";

			jgd.setAlfa(calculateAlfa());
			if(jgd.getAlfa()>=0){
				answers+="<p>Az Ön alfa-pesszimizmus értéke: <font color=#FF0000>"+df.format(jgd.getAlfa())+"</font></p></html>";
			}else{
				answers+="<p>Az Ön alfa-pesszimizmus értéke: <font color=#FF0000> Válaszai alapján nem meghatározható.</font></p></html>";
			}
			jk0003.getGameResults().setText(answers);
			if(sendDataToPhp()){
		        jk0003.showMessage("mysqlOK");
		        jgd.setToExcel(true);
		        return "<p>A tesztnek vége. Megtekintheti az eredményeket.</p>";
			}else{
				closeGame();
				return "<p>Az eredményeket nem sikerült menteni, így nem tudjuk azokat feldolgozni.</p>";
			}
			
			
		}
		jgd.setActRound(round+1);
		String[] colL= {jgd.getE1(),jgd.getE2()};
		String[] rowL= {jgd.getA1(),jgd.getA2()};
		
		if("up".equals(order)){
			double x=(jgd.getStep()*(double)round);
			jgd.setActDouble(x);
			StringBuffer sb = new StringBuffer("<table border=1 width="+tableWidth+"><tr><td align=center>/</td>");
			for(int i=0;i<colL.length;i++){
				sb.append("<td>"+colL[i]+"</td>");
			}
			sb.append("</tr>");
			sb.append("<tr>");
			sb.append("<td>"+rowL[0]+"</td>");
			sb.append("<td>1</td><td>0</td>");
			sb.append("</tr>");
			sb.append("<tr>");
			sb.append("<td>"+rowL[1]+"</td>");
			sb.append("<td>"+df.format(x)+"</td><td>"+df.format(x)+"</td>");
			sb.append("</tr>");
			sb.append("</table>");
			return sb.toString();
		}else if("down".equals(order)){
				double x=1.0-(jgd.getStep()*(double)round);
				jgd.setActDouble(x);
				StringBuffer sb = new StringBuffer("<table border=1 width="+tableWidth+"><tr><td align=center>/</td>");
				for(int i=0;i<colL.length;i++){
					sb.append("<td>"+colL[i]+"</td>");
				}
				sb.append("</tr>");
				sb.append("<tr>");
				sb.append("<td>"+rowL[0]+"</td>");
				sb.append("<td>1</td><td>0</td>");
				sb.append("</tr>");
				sb.append("<tr>");
				sb.append("<td>"+rowL[1]+"</td>");
				sb.append("<td>"+df.format(x)+"</td><td>"+df.format(x)+"</td>");
				sb.append("</tr>");
				sb.append("</table>");
				return sb.toString();
		}else if("random".equals(order)){
			double actChoice;
			if((jgd.getRounds()+1)-jgd.getActRound()>0){
				Random rnd=new Random();
				int randomNumber=rnd.nextInt((jgd.getRounds()+1)-jgd.getActRound());
				actChoice=jgd.getRandomNums()[randomNumber];
				jgd.getRandomNums()[randomNumber]=jgd.getRandomNums()[(jgd.getRounds()+1)-jgd.getActRound()];
			}else{
				actChoice=jgd.getRandomNums()[0];
			}
			double x=actChoice;
			jgd.setActDouble(x);
			StringBuffer sb = new StringBuffer("<table border=1 width="+tableWidth+"><tr><td align=center>/</td>");
			for(int i=0;i<colL.length;i++){
				sb.append("<td>"+colL[i]+"</td>");
			}
			sb.append("</tr>");
			sb.append("<tr>");
			sb.append("<td>"+rowL[0]+"</td>");
			sb.append("<td>1</td><td>0</td>");
			sb.append("</tr>");
			sb.append("<tr>");
			sb.append("<td>"+rowL[1]+"</td>");
			sb.append("<td>"+df.format(x)+"</td><td>"+df.format(x)+"</td>");
			sb.append("</tr>");
			sb.append("</table>");
			return sb.toString();
	}
		return "";
	}

	@Override
	public void playGame() {
		if(!jgd.isSaved()){
			if(jgd.getClicked()==null){
				jk0003.getA1().setEnabled(true);
				jk0003.getA2().setEnabled(true);
				jk0003.getIndifferent().setEnabled(true);
				
			}else if(jgd.getClicked().equals(jgd.getA1())){
		    	jgd.getAns().add(new Answer(jgd.getE1(),jgd.getE2(),jgd.getA1(),jgd.getA2(),jgd.getActDouble(),jgd.getA1(),jgd.getActSex(),jgd.getActAge()));
				jgd.setGameInputHtmlContent("<html>"+createGameContent(jgd.getOrder(),jgd.getActRound())+"</html>");
		   	  	jk0003.getGameInputContent().setText(jgd.getGameInputHtmlContent());
		   	  	
			}else if(jgd.getClicked().equals(jgd.getA2())){
				
				jgd.getAns().add(new Answer(jgd.getE1(),jgd.getE2(),jgd.getA1(),jgd.getA2(),jgd.getActDouble(),jgd.getA2(),jgd.getActSex(),jgd.getActAge()));
	
				jgd.setGameInputHtmlContent("<html>"+createGameContent(jgd.getOrder(),jgd.getActRound())+"</html>");
		    	jk0003.getGameInputContent().setText(jgd.getGameInputHtmlContent()); 
		    	
			}else if(jgd.getClicked().equals("Indifferens")){
				
				jgd.getAns().add(new Answer(jgd.getE1(),jgd.getE2(),jgd.getA1(),jgd.getA2(),jgd.getActDouble(),"Indifferens",jgd.getActSex(),jgd.getActAge()));
				
				jgd.setGameInputHtmlContent("<html>"+createGameContent(jgd.getOrder(),jgd.getActRound())+"</html>");
		    	jk0003.getGameInputContent().setText(jgd.getGameInputHtmlContent());
		    	
			}
		}
	}

	private double calculateAlfa() {
		// alfa=1-x
		int change=-1;
		int[] changePos=new int[3];
		int i=0,p=0;
		Answer prev=new Answer();
		prev.setAn2("");
		for(Answer ans: jgd.getAns()){
			if(!prev.getAn2().equals(ans.getAn2())){
				if(change>=0){
					changePos[p]=i;
					p++;
				}
				change++;
				if(change>2){
					break;
				}
				prev=ans;
			}
			i++;
		}
		if(change==0){
			return -1.0;
		}
		if(change==1){
			if(!jgd.getAns().get(changePos[0]).getAn2().equals("Indifferens")){
				return 1.0-((jgd.getAns().get(changePos[0]).getAn1()+jgd.getAns().get(changePos[0]-1).getAn1())/2);
			}else{
				double db=0.0;
				double avg=0.0;
				for(int k=changePos[0];k<jgd.getAns().size();k++){
					if(jgd.getAns().get(k).getAn2().equals("Indifferens")){
						avg+=jgd.getAns().get(k).getAn1();
						db++;
					}else{
						break;
					}
				}
				return 1.0-(avg/db);
			}
		}
		if(change==2){
			String firstChoice=jgd.getAns().get(changePos[0]-1).getAn2();
			String secondChoice=jgd.getAns().get(changePos[1]).getAn2();
			if(firstChoice.equals(secondChoice)){
				return -1.0;
			}else{
				double db=0.0;
				double avg=0.0;
				for(int k=0;k<jgd.getAns().size();k++){
					if(jgd.getAns().get(k).getAn2().equals("Indifferens")){
						avg+=jgd.getAns().get(k).getAn1();
						db++;
					}
				}
				return 1.0-(avg/db);
			}
		}
		if(change>2){
			return -1.0;
		}
		
		return 100000.0;
	}
	
	public Jatek0003GameData getJgd() {
		return jgd;
	}

	public Jatek0003Panel getJk0003() {
		return jk0003;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		String ac = e.getActionCommand();
	      if(ac.equals(jgd.getA1())) {
	    	  jgd.setClicked(jgd.getA1());
	    	  playGame();
	      }else if(ac.equals(jgd.getA2())){
	    	  jgd.setClicked(jgd.getA2());
	    	  playGame();
	      }else if(ac.equals("Indifferens")){
	    	  jgd.setClicked("Indifferens");
	    	  playGame();
	      }else if(ac.equals("sex")){
	    	  JComboBox cbsex = (JComboBox)e.getSource();
	          jgd.setActSex((String)cbsex.getSelectedItem());	 
	      }else if(ac.equals("age")){
	    	  JComboBox cbage = (JComboBox)e.getSource();
	          jgd.setActAge((int)(Integer)cbage.getSelectedItem());

	      }
	}

}
