package theGhastModding.midiPlayer.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;

import org.hyperic.sigar.CpuInfo;
import org.hyperic.sigar.Mem;
import org.hyperic.sigar.Sigar;

import theGhastModding.midiPlayer.main.TheGhastMidiPlayerMain;
import theGhastModding.utils.math.ByteConverters;
import java.awt.Font;

@SuppressWarnings("serial")
public class Telemetry extends JDialog {
	
	private JTextField textField;
	private JTextField textField_1;
	private JTextArea textArea;
	
	public Telemetry() {
		super(TheGhastMidiPlayerMain.frame, "Telemetry");
		long totalMemory = -1;
		String[] cpuNames = new String[] {"Error retreiving CPU specs"};
		try {
			Sigar sigar = new Sigar();
			Mem mem = sigar.getMem();
			totalMemory = mem.getTotal();
			CpuInfo[] cpuInfos = sigar.getCpuInfoList();
			cpuNames = new String[cpuInfos.length];
			for(int i = 0; i < cpuInfos.length; i++) {
				cpuNames[i] = cpuInfos[i].getModel();
			}
		}catch(Exception e) {
			JOptionPane.showMessageDialog(TheGhastMidiPlayerMain.frame, "Error getting system information: " + e.getMessage() + ". Some specs may be incorrect", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
		}
		setModal(true);
		setLocationRelativeTo(TheGhastMidiPlayerMain.frame);
		this.setResizable(false);
		this.getContentPane().setLayout(null);
		this.getContentPane().setPreferredSize(new Dimension(400,405));
		
		JLabel lblYourComment = new JLabel("Your comment:");
		lblYourComment.setBounds(10, 61, 380, 14);
		getContentPane().add(lblYourComment);
		
		textArea = new JTextArea();
		textArea.setFont(new Font("Dialog", Font.PLAIN, 11));
		JScrollPane textScroller = new JScrollPane(textArea);
		textScroller.setBorder(new LineBorder(Color.BLUE));
		textArea.setWrapStyleWord(true);
		textArea.setLineWrap(true);
		textScroller.setBounds(10, 86, 380, 103);
		getContentPane().add(textScroller);
		
		JCheckBox chckbxCheckIfThis = new JCheckBox("Check, if this is a bug report");
		chckbxCheckIfThis.setBounds(10, 196, 380, 23);
		getContentPane().add(chckbxCheckIfThis);
		
		JLabel lblYournicknamerequired = new JLabel("Your (Nick)Name (Required): ");
		lblYournicknamerequired.setBounds(10, 11, 140, 14);
		getContentPane().add(lblYournicknamerequired);
		
		textField = new JTextField();
		textField.setBounds(160, 8, 230, 20);
		getContentPane().add(textField);
		textField.setColumns(10);
		
		JLabel lblYourPcSpecs = new JLabel("Your PC specs (these will be sent to the developer):");
		lblYourPcSpecs.setBounds(10, 226, 380, 14);
		getContentPane().add(lblYourPcSpecs);
		
		JLabel lblProcessors = new JLabel("Processors:");
		lblProcessors.setBounds(10, 251, 68, 14);
		getContentPane().add(lblProcessors);
		
		JTextArea textArea_1 = new JTextArea();
		textArea_1.setFont(new Font("Dialog", Font.PLAIN, 11));
		textArea_1.append("Warning! CPU cores are listed as seperate processors.\n");
		for(String s:cpuNames) {
			textArea_1.append(s + "\n");
		}
		textArea_1.setEditable(false);
		JScrollPane textScroller_1 = new JScrollPane(textArea_1);
		textScroller_1.setBorder(new LineBorder(Color.BLUE));
		textScroller_1.setBounds(74, 251, 316, 63);
		getContentPane().add(textScroller_1);
		
		JLabel lblInstalledRam = new JLabel("Installed RAM: " + Long.toString(totalMemory) + " bytes (" + Double.toString((double)totalMemory / 1024D / 1024D / 1024D) + "GB)");
		lblInstalledRam.setBounds(10, 325, 380, 14);
		getContentPane().add(lblInstalledRam);
		
		JLabel lblOs = new JLabel("OS: " + System.getProperty("os.name"));
		lblOs.setBounds(10, 350, 380, 14);
		getContentPane().add(lblOs);
		
		JButton btnSend = new JButton("Send");
		btnSend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(textField.getText().isEmpty()) {
					JOptionPane.showMessageDialog(TheGhastMidiPlayerMain.frame, "You need to give us your name, please", "Error", JOptionPane.ERROR_MESSAGE);
					return;
				}
				if(textField.getText().length() > 250) {
					JOptionPane.showMessageDialog(TheGhastMidiPlayerMain.frame, "Your Name is too long. 250 Characters max please", "Error", JOptionPane.ERROR_MESSAGE);
					return;
				}
				try {
					send(collectInfo(textField.getText() + " (" + textField_1.getText() + ")", textArea.getText(), chckbxCheckIfThis.isSelected()), textField.getText());
				} catch(Exception e2) {
					JOptionPane.showMessageDialog(TheGhastMidiPlayerMain.frame, "Error sending telemetry info: " + e2.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
					e2.printStackTrace();
					setVisible(false);
					return;
				}
			}
		});
		btnSend.setBounds(301, 375, 89, 23);
		getContentPane().add(btnSend);
		
		JButton btnCancel = new JButton("Cancel");
		btnCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setVisible(false);
			}
		});
		btnCancel.setBounds(202, 375, 89, 23);
		getContentPane().add(btnCancel);
		
		JLabel lblYourEmailOr = new JLabel("Your e-mail OR Discord ID:");
		lblYourEmailOr.setBounds(10, 36, 140, 14);
		getContentPane().add(lblYourEmailOr);
		
		textField_1 = new JTextField();
		textField_1.setBounds(160, 33, 230, 20);
		getContentPane().add(textField_1);
		textField_1.setColumns(10);
		
		pack();
	}
	
	public static String collectInfo(String name, String comment, boolean bug) throws Exception {
		String toReturn = "Telemetry Info from: " + name + "\n\n";
		Sigar sigar = new Sigar();
		Mem mem = sigar.getMem();
		toReturn += "Total installed RAM: " + Long.toString(mem.getTotal()) + " (" + Double.toString((double)mem.getTotal() / 1024D / 1024D / 1024D) + "GB)";
		toReturn += "\nInstalled processors/cores:\n";
		for(CpuInfo ci:sigar.getCpuInfoList()) {
			toReturn += " - " + ci.getModel() + "\n";
		}
		toReturn += "Installed OS: " + System.getProperty("os.name");
		if(!comment.isEmpty()) {
			toReturn += "\n\nThe following " + (bug ? "Bug Report" : "Comment") + " has been attached:\n";
			toReturn += comment;
		}
		return toReturn;
	}
	
	public void send(String infoText, String name) {
		String[] IPs = null;
		try {
			URL website = new URL("https://www.dropbox.com/s/r2s1hvoynclk78j/IP.txt?dl=1");
			InputStream stream = website.openStream();
			String s = "";
			while(stream.available() > 0) {
				s += (char)(byte)stream.read();
			}
			IPs = s.split("\n");
		} catch(Exception e) {
			JOptionPane.showMessageDialog(this, "Error retrieving Server IP. You probably have no Internet connection-", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
			return;
		}
		for(int tryCount = 0; tryCount < IPs.length; tryCount++) {
			Socket clientSocket;
			try {
				String IP = IPs[tryCount].split(":")[0];
				int port = Integer.parseInt(IPs[tryCount].split(":")[1].trim());
				System.out.println(IP);
				System.out.println(port);
				clientSocket = new Socket(IP, port);
			} catch(Exception e) {
				if(tryCount + 1 >= IPs.length) {
					e.printStackTrace();
					JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
					return;
				}
				System.err.println("Error establishing connection to telemetry server. Trying next available IP.");
				e.printStackTrace();
				continue;
			}
			try {
				InputStream in = clientSocket.getInputStream();
				OutputStream out = clientSocket.getOutputStream();
				byte[] data = new byte[512];
				data[0] = (byte)name.length();
				char[] chars = name.toCharArray();
				for(int i = 0; i < name.length(); i++) {
					data[(byte)(i + 1)] = (byte)chars[i];
				}
				byte[] infoLength = ByteConverters.shortToBytes((short)infoText.length());
				data[name.length() + 1] = infoLength[0];
				data[name.length() + 2] = infoLength[1];
				out.write(data);
				out.flush();
				try {
					Thread.sleep(5000);
				}catch(Exception e) {
					e.printStackTrace();
				}
				if(in.available() <= 0) {
					if(tryCount + 1 >= IPs.length) {
						JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
						try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
						return;
					}
					System.err.println("Telemetry server timed out. Trying next available IP.");
					try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
					continue;
				}
				String response = "";
				while(in.available() > 0) {
					response += (char)(byte)in.read();
				}
				if(!response.equals("Acknowledged")) {
					if(tryCount + 1 >= IPs.length) {
						JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
						try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
						return;
					}
					System.err.println("Telemetry responded incorrectly (" + response + "). Trying next available IP.");
					try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
					continue;
				}
				int i = 0;
				while(i < infoText.length()) {
					String subs = infoText.substring(i, (infoText.length() < i + 512 ? infoText.length() : i + 512));
					char[] subchars = subs.toCharArray();
					data = new byte[512];
					for(int j = 0; j < 512; j++) {
						data[j] = j >= subchars.length ? (byte)' ' : (byte)subchars[j];
					}
					out.write(data);
					out.flush();
					i += 512;
				}
				try {
					Thread.sleep(5000);
				}catch(Exception e) {
					e.printStackTrace();
				}
				if(in.available() <= 0) {
					if(tryCount + 1 >= IPs.length) {
						JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
						try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
						return;
					}
					System.err.println("Telemetry server timed out. Trying next available IP.");
					try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
					continue;
				}
				response = "";
				while(in.available() > 0) {
					response += (char)(byte)in.read();
				}
				if(!response.equals("Received")) {
					if(tryCount + 1 >= IPs.length) {
						JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
						try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
						return;
					}
					System.err.println("Telemetry responded incorrectly (" + response + "). Trying next available IP.");
					try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
					continue;
				}
			} catch(Exception e) {
				if(tryCount + 1 >= IPs.length) {
					e.printStackTrace();
					JOptionPane.showMessageDialog(this, "All telemetry Servers appear to be offline. Please check your Internet connection or try again later.", "Error", JOptionPane.ERROR_MESSAGE);
					try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
					return;
				}
				System.err.println("Error communicating with telemetry server. Trying next available IP.");
				e.printStackTrace();
				continue;
			}
			try { clientSocket.close(); } catch(Exception e2) { e2.printStackTrace(); }
			JOptionPane.showMessageDialog(TheGhastMidiPlayerMain.frame, "Successfully sent telemetry info", "Success", JOptionPane.INFORMATION_MESSAGE);
			setVisible(false);
			return;
		}
	}
	
}