package com.izforge.izpack.panels;

import com.izforge.izpack.installer.InstallData;
import com.izforge.izpack.installer.InstallerFrame;
import com.izforge.izpack.util.AbstractUIHandler;

import java.io.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Vector;
import java.util.Iterator;

import net.n3.nanoxml.*;

/**
 * @author dmitry.antonov
 */
public class DBSettingsPanel extends UserInputPanel {

    public static String[] exec(String[] command) {
        System.out.println("executing command");
        for (int i = 0; i < command.length; i++) {
            String s = command[i];
            System.out.println("cmd i = " + s);
        }
        List result = new ArrayList();
        try {
            Process proc = Runtime.getRuntime().exec(command);
            InputStream stderr = proc.getErrorStream();
            InputStream stin = proc.getInputStream();
            InputStreamReader isr = new InputStreamReader(stin);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println("added line = " + line);
                result.add(line);
            }
            proc.waitFor();
        } catch (Throwable t) {
            t.printStackTrace();
        }
        System.out.println("executing result is " + result);
        return (String[]) result.toArray(new String[result.size()]);
    }
    
    private static final String INSTALL_MYSQL = "installMySQL";
    private static final String MYSQL_PATH = "MYSQL_PATH";
    private static final String MYSQL_PORT = "MYSQL_PORT";
    private static final String DB_LOGIN = "DB_USER";
    private static final String DB_PASSWORD = "DB_PASSWORD";
    private static final String DB_PASS = "DB_PASSWORD";
    private static final String DB_NAME = "DB_NAME";

    private static final String DB_UPDATE_CONFIG = "db_update_config";
    private static final String DB_CORE_VERSION_ATTR = "core_version";
    private static final String DB_APP_VERSION_ATTR = "app_version";
    private static final String DB_ACTION_ATTR = "action";


    private static final String DB_ACTION = "DB_ACTION";

    private String action = DBActions.CREATE;

    private interface DBActions {
        String UPDATE = "UPDATE";
        String CREATE = "CREATE";
        String NONE = "NONE";
    }

    private static class DBVersion {
        private static final String CORE_VERSION = "DB_CORE_VERSION_ATTR";
        private static final String APP_VERSION = "DB_APP_VERSION_ATTR";
        public final String coreVersion;
        public final String appVersion;
        public final String action;
        public DBVersion(XMLElement element) {
            this.coreVersion = element.getAttribute(DB_CORE_VERSION_ATTR);
            this.appVersion = element.getAttribute(DB_APP_VERSION_ATTR);
            this.action = element.getAttribute(DB_ACTION_ATTR);
        }
        public boolean isMatched(String[] dbData) {
            System.out.println("db versions = " + coreVersion + " and " + appVersion);
            boolean isCoreVersionMatched = false;
            boolean isAppVersionMatched = false;
            for (int i = 0; i < dbData.length; i++) {
                String line = dbData[i];
                System.out.println("compare line = " + line);
                if (line.contains(CORE_VERSION) && line.contains(coreVersion)) {
                    isCoreVersionMatched = true;
                }
                if (line.contains(APP_VERSION) && line.contains(appVersion)) {
                    isAppVersionMatched = true;
                }
            }
            return isAppVersionMatched && isCoreVersionMatched;
        }
    }

    public DBSettingsPanel(InstallerFrame parent, InstallData installData) {
        //Autogenerate
        super(parent, installData);
    }


    private String[] getDBNames(String mySqlPath) {
        File file = new File(mySqlPath + File.separator + "data");
        if (file.exists() && file.isDirectory()) {
            File[] files = file.listFiles();
            List result = new ArrayList();
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                    result.add(files[i].getName());
                }
            }
            return (String[]) result.toArray(new String[0]);
        }
        else {
            return new String[0];
        }
    }

    private boolean isDBNameUnique(String dbName) {
        try {
            System.out.println("Checking DB name");
            dbName = dbName.toUpperCase();
            if (idata.getVariable(INSTALL_MYSQL).equals("no")) {
                String[] dbnames = getDBNames(idata.getVariable(MYSQL_PATH));
                for (int i = 0; i < dbnames.length; i++) {
                    String currentLine = dbnames[i];
                    if (currentLine.toUpperCase().contains(dbName)) {
                        System.out.println("Checkin db version");
                        action = checkDBVersion();
                        if (action == DBActions.NONE) {
                            return askQuestion("QueWeb Database Warning", "QueWeb DB with specified name already exists. " +
                                    "DB version is actual, no actions will be performed, existing data will be left. Do you agree?",
                                    AbstractUIHandler.CHOICES_YES_NO, AbstractUIHandler.ANSWER_NO) == AbstractUIHandler.ANSWER_YES;
                        } else if (action.startsWith(DBActions.UPDATE)) {
                            return askQuestion("QueWeb Database Warning", "QueWeb DB with specified name already exists but its version is obsolete. " +
                                    "Update will be performed. Do you agree?", AbstractUIHandler.CHOICES_YES_NO,
                                    AbstractUIHandler.ANSWER_NO) == AbstractUIHandler.ANSWER_YES;
                        }
                    }
                }
            }
            return true;
        }
        finally {
            idata.setVariable(DB_ACTION, action);
        }
    }

    private boolean isPasswordConfimationValid() {
        if (idata.getVariable(DB_PASS + '1').equals(idata.getVariable(DB_PASS + '2'))) {
            idata.setVariable(DB_PASS, idata.getVariable(DB_PASS + '1'));
            return true;
        }
        else {
            emitError("QueWeb DB password error", "The password was not correctly confirmed. Please ensure that the password and confirmation match exactly.");            
            return false;
        }
    }

    /*--------------------------------------------------------------------------*/
    /*--------------------------------------------------------------------------*/
    public boolean isValidated() {
        return super.isValidated() && isPasswordConfimationValid() && 
                isDBNameUnique(idata.getVariable("DB_NAME"));
    }

    private void createTmpFiles(String mySqlBinPath) throws IOException {
        System.out.println("creating tmp file");
        //query
        PrintWriter writer = new PrintWriter(mySqlBinPath + "check.sql");
        writer.print("select prop_id, prop_val from qx_sys_prop where " +
                "prop_id like '%VERSION%'");
        writer.close();

        writer = new PrintWriter(mySqlBinPath + "check.bat");
        writer.print("cd " + mySqlBinPath + "\n");
        writer.print("mysql.exe ");
        writer.print(" --user=" + idata.getVariable(DB_LOGIN));
        writer.print(" --password=" + idata.getVariable(DB_PASSWORD));
        writer.print(" --port=" + idata.getVariable(MYSQL_PORT));
        writer.print(" " + idata.getVariable(DB_NAME) + " < check.sql");
        writer.close();

        System.out.println("files created");
    }

    private void removeTmpFiles(String mySqlBinPath) {
        new File(mySqlBinPath + "check.sql").delete();
        new File(mySqlBinPath + "check.bat").delete();
    }

    private String checkDBVersion() {
        try {
            InputStream  is = parent.getResource(DB_UPDATE_CONFIG);
            StdXMLParser parser = new StdXMLParser();
            parser.setBuilder(new StdXMLBuilder());
            parser.setValidator(new NonValidator());
            parser.setReader(new StdXMLReader(is));
            // get the data
            XMLElement data = (XMLElement) parser.parse();
            Vector actions = data.getChildrenNamed("action");
            DBVersion[] versions = new DBVersion[actions.size()];
            int index = 0;
            for (Iterator iterator = actions.iterator(); iterator.hasNext();) {
                versions[index++] = new DBVersion((XMLElement) iterator.next());
            }

            String mySqlBinPath = idata.getVariable(MYSQL_PATH) + File.separator + "bin" + File.separator;
            createTmpFiles(mySqlBinPath);
            String[] result = exec(new String[]{
                    mySqlBinPath + "check.bat"
            });
            removeTmpFiles(mySqlBinPath);
            /*DBVersion[] versions = new DBVersion[]{
                    new DBVersion("68", "55", DBActions.UPDATE),
                    new DBVersion("75", "57", DBActions.NONE)
            };*/
            System.out.println("checking versions");
            for (int i = 0; i < versions.length; i++) {
                DBVersion version = versions[i];
                if (version.isMatched(result)) {
                    System.out.println("found action " + version.action);
                    return version.action;
                }
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        return DBActions.CREATE;
    }

    

}
