package theGhastModding.midiToolbox.main;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.SwingConstants;

@SuppressWarnings("serial")
public class LoginPanel extends JPanel {
	
	private JPasswordField passwordField;
	
	/*
	 * swirls (Shangai teahouse), funnels (in melody of the black 2 in the red zone and evans part), square  swirls  (rektonance and reach for the moon) death ending (silent notes like in bad apples ending) crash part spam (amount of bars) and just standard made up patterns you make up, you can use your picture to midi to create a midi of patterns you draw and then put those as presets
	 */
	
	public LoginPanel(){
		setPreferredSize(new Dimension(700, 300));
		setLayout(null);
		
		JLabel lblLocked = new JLabel("Some functions are locked for normal users. Please enter the Password to unlock them");
		lblLocked.setFont(new Font("Dialog", Font.BOLD, 16));
		lblLocked.setForeground(Color.RED);
		lblLocked.setHorizontalAlignment(SwingConstants.CENTER);
		lblLocked.setBounds(10, 11, 666, 21);
		add(lblLocked);
		
		passwordField = new JPasswordField();
		passwordField.setHorizontalAlignment(SwingConstants.CENTER);
		passwordField.setBounds(20, 43, 656, 20);
		add(passwordField);
		
		JButton btnUnlock = new JButton("Unlock");
		
		JButton btnLoginFromOffline = new JButton("Unlock from offline key");
		btnLoginFromOffline.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				boolean success = readOfflineKey();
				if(success){
					remove(passwordField);
					remove(lblLocked);
					remove(btnUnlock);
					remove(btnLoginFromOffline);
					JLabel lblCorrectLogin = new JLabel("Login Correct, Features have been unlocked");
					lblCorrectLogin.setFont(new Font("Dialog", Font.BOLD, 16));
					lblCorrectLogin.setHorizontalAlignment(SwingConstants.CENTER);
					lblCorrectLogin.setBounds(10, 11, 666, 21);
					add(lblCorrectLogin);
					repaint();
				}
			}
		});
		btnLoginFromOffline.setBounds(264, 111, 168, 26);
		add(btnLoginFromOffline);
		
		btnUnlock.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				passwordField.setEditable(false);
				btnUnlock.setEnabled(false);
				char[] enteredPassword = passwordField.getPassword();
				byte[] encryptedPassword = getEncryptedPassword();
				if(enteredPassword.length != encryptedPassword.length){
					for(int i = 0; i < enteredPassword.length; i++){
						enteredPassword[i] = 'l';
					}
					encryptedPassword = null;
					JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "The password is incorrect", "Wrong Password", JOptionPane.ERROR_MESSAGE);
					passwordField.setEditable(true);
					btnUnlock.setEnabled(true);
					return;
				}
				for(int i = 0; i < enteredPassword.length; i++){
					int number = encryptedPassword[i];
					number += 9;
					if(number > 255){
						number = number - 255;
					}
					if(number != (byte)enteredPassword[i]){
						for(int j = 0; j < enteredPassword.length; j++){
							enteredPassword[j] = 'l';
						}
						encryptedPassword = null;
						JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "The password is incorrect", "Wrong Password", JOptionPane.ERROR_MESSAGE);
						passwordField.setEditable(true);
						btnUnlock.setEnabled(true);
						return;
					}
				}
				remove(passwordField);
				remove(lblLocked);
				remove(btnUnlock);
				remove(btnLoginFromOffline);
				JLabel lblCorrectLogin = new JLabel("Login Correct, Features have been unlocked");
				lblCorrectLogin.setFont(new Font("Dialog", Font.BOLD, 16));
				lblCorrectLogin.setHorizontalAlignment(SwingConstants.CENTER);
				lblCorrectLogin.setBounds(10, 11, 666, 21);
				add(lblCorrectLogin);
				JButton btnOffline = new JButton("No internet for a while? Generate offline key here");
				btnOffline.setBounds(10, 75, 666, 26);
				add(btnOffline);
				btnOffline.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
						int option = JOptionPane.showConfirmDialog(TGMMIDIToolbox.frame, "MIDI Toolbox requires a internet connection to download the correct password.\n You can generate an offline key to gain access to the locked features for a limited amount of time,\n without needing internet. Do you really want to generate an offline key?", "Question",JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
						if(option == 0){
							JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Logging in with an offline key still requires a password.\n For this, you can set your own password.", "Information", JOptionPane.INFORMATION_MESSAGE);
							String s = JOptionPane.showInputDialog(TGMMIDIToolbox.frame, "Please enter password for offline key", "Input", JOptionPane.QUESTION_MESSAGE);
							boolean success = generateOfflineKey(s);
							if(success){
								JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Offline key has been created. Please be aware that the key only works on your computer \n and only for two weeks. You can find the key in the same folder as the program under the filename \"offline.dat\"", "Message", JOptionPane.INFORMATION_MESSAGE);
							}
						}
					}
				});
				repaint();
			}
		});
		btnUnlock.setBounds(299, 75, 98, 26);
		add(btnUnlock);
		
	}
	
	public boolean generateOfflineKey(String s){
		try {
			FileOutputStream fos = new FileOutputStream(new File("offline.dat"));
			fos.write(s.length());
			byte[] data = s.getBytes();
			byte[] encrypted = new byte[data.length];
			for(int i = 0; i < data.length; i++){
				int number = data[i];
				number -= 22;
				if(number < 0){
					number = 256 + number;
				}
				encrypted[i] = (byte)number;
			}
			fos.write(encrypted);
			String username = System.getProperty("user.name");
			fos.write(username.length());
			data = s.getBytes();
			encrypted = new byte[data.length];
			for(int i = 0; i < data.length; i++){
				int number = data[i];
				number -= 25;
				if(number < 0){
					number = 256 + number;
				}
				encrypted[i] = (byte)number;
			}
			fos.write(encrypted);
			String currentTime = Long.toString(System.currentTimeMillis());
			fos.write(currentTime.length());
			fos.write(currentTime.getBytes());
			fos.flush();
			fos.close();
		} catch(Exception e){
			JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Error creating offline key", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public boolean readOfflineKey(){
		//1209600000
		try {
			if(!new File("offline.dat").exists()){
				JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Error finding offline key. The key needs to be in the same directory as the program", "Error", JOptionPane.ERROR_MESSAGE);
				return false;
			}
			FileInputStream fis = new FileInputStream(new File("offline.dat"));
			int length = fis.read();
			byte[] b2 = new byte[length];
			fis.read(b2);
			PasswordInputFrame pif = new PasswordInputFrame(TGMMIDIToolbox.frame);
			pif.setLocationRelativeTo(this);
			char[] passw = pif.getPassword();
			if(passw.length != b2.length){
				JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "The password is incorrect", "Wrong Password", JOptionPane.ERROR_MESSAGE);
				fis.close();
				return false;
			}
			for(int i = 0; i < passw.length; i++){
				int number = b2[i];
				number += 22;
				if(number > 255){
					number = number - 255;
				}
				if(number != (byte)passw[i]){
					for(int j = 0; j < passw.length; j++){
						passw[j] = 'l';
					}
					passw = null;
					pif = null;
					JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "The password is incorrect", "Wrong Password", JOptionPane.ERROR_MESSAGE);
					fis.close();
					return false;
				}
			}
			for(int j = 0; j < passw.length; j++){
				passw[j] = 'l';
			}
			passw = null;
			pif = null;
			
			fis.close();
		}catch(Exception e){
			JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Error reading offline key", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public byte[] getEncryptedPassword(){
		try {
			FileOutputStream fos;
        	URL website = new URL("https://www.dropbox.com/s/9qjytqd76rum6s3/password.dat?dl=1");
        	ReadableByteChannel rbc = Channels.newChannel(website.openStream());
        	fos = new FileOutputStream("pass.dat");
        	fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        	fos.close();
		}catch(Exception e){
			JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Error downloading current password", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
			return null;
		}
		byte[] password;
		try {
			FileInputStream fis = new FileInputStream(new File("pass.dat"));
			int dataLength = fis.read();
			byte[] data = new byte[dataLength * 2];
			fis.read(data);
			fis.close();
			password = new byte[dataLength];
			boolean read = true;
			for(int i = 0; i < data.length; i++){
				if(read){
					password[i / 2] = data[i];
					read = false;
				}else{
					read = true;
				}
			}
		} catch(Exception e){
			JOptionPane.showMessageDialog(TGMMIDIToolbox.frame, "Error reading password", "Error", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
			return null;
		}
		new File("pass.dat").delete();
		return password;
	}
}
