package kamicharserver;

import java.io.*;
import java.sql.*;

import java.nio.ByteBuffer;

public class KamiProcessor {

    public static String sWorldIP;
    Statement stState;
    String sQuery;
    ResultSet resResult;
    //KamiCommand kc;

    //
    // Constructor
    public KamiProcessor() {
    }

    public void setStatement(Statement st) {
        stState = st;
    }

    // =========================================================================
    // Main Methods
    //
    public void respond(KamiCommand kc_comm, KamiUser ku) throws IOException, SQLException {

        ByteBuffer bb;

        sQuery = "";

        switch (kc_comm.getID()) {

            // login request response
            case 1:

                sQuery = "SELECT * FROM users WHERE login=\"" + kc_comm.get(0) + "\" AND password=\"" + kc_comm.get(1) + "\"";
                resResult = stState.executeQuery(sQuery);
                bb = ByteBuffer.allocate(32);
                if (!resResult.next()) {
                    bb.putInt(-1);
                    bb.putInt(-1);
                    bb.putInt(-1);
                } else {
                    bb.putInt(resResult.getInt("id"));
                    bb.putInt(resResult.getInt("type"));
                    bb.putInt(resResult.getInt("house_id"));
                }

                sQuery = "SELECT * FROM users_chars WHERE id IN ( SELECT id FROM users WHERE login=\"" + kc_comm.get(0) + "\" AND password=\"" + kc_comm.get(1) + "\")";
                resResult = stState.executeQuery(sQuery);
                if (!resResult.next()) {
                    bb.put((byte) 0);
                } else {
                    bb.put((byte) 1);
                }

                //command
                ku.sendCommand(2, bb.array(), bb.position());
                System.out.println("C02 send: log-in accepted");
                System.out.println("Query send: " + sQuery);

                break;

            // characters request
            case 3:
                sQuery = "SELECT * FROM users_chars WHERE id=" + kc_comm.get(0);
                resResult = stState.executeQuery(sQuery);
                System.out.println("Query send: " + sQuery);
                if (!resResult.next()) {
                    break;
                }
                int cid = 0;
                do {
                    cid = resResult.getByte("cid");
                    if (ku.checkCID(cid)) {
                        continue;
                    }
                    ku.addChar(KamiChar.getFromResult(resResult));

                } while (resResult.next());

                for (KamiChar kc_tmp : ku.getChars()) {
                    if (kc_tmp == null) {
                        break;
                    }
                    KamiCommand kc = kc_tmp.getCommand();

                    //id
                    bb = ByteBuffer.allocate(5022);

                    bb.putInt((Integer) kc.get(0));
                    bb.put((Byte) kc.get(1));
                    bb.put(getUTF((String) kc.get(2)));
                    bb.put(getUTF((String) kc.get(3)));
                    bb.putInt((Integer) kc.get(4));
                    bb.putInt((Integer) kc.get(5));
                    bb.put(getUTF((String) kc.get(6)));
                    bb.put(getUTF((String) kc.get(7)));
                    bb.put((Byte) kc.get(8));
                    bb.put((Byte) kc.get(9));
                    bb.putInt((Integer) kc.get(10));
                    bb.putInt((Integer) kc.get(11));
                    bb.putInt((Integer) kc.get(12));
                    bb.putInt((Integer) kc.get(13));

                    ku.sendCommand(4, bb.array(), bb.position());
                    System.out.println("C04 send: character info");
                }

                break;

            //add char
            case 5:

                if (ku.getChars().length > 5) {
                    return;
                }
                ku.addChar(new KamiChar((Integer) kc_comm.get(0), (Byte) kc_comm.get(1), (String) kc_comm.get(2), (String) kc_comm.get(3), (String) kc_comm.get(4)));
                sQuery = "INSERT INTO users_chars(id,cid,name,map,posx,posy,sheet_file,colors,class,level,stats,hp,sp,exp,gold) VALUES(" + kc_comm.get(0) + ", " + kc_comm.get(1) + ", \"" + kc_comm.get(2) + "\", \"w/world/start.map\", 500, 500, \"" + kc_comm.get(3) + "\", \"" + kc_comm.get(4) + "\", 0, 1, 0x01010101, 0x000f000f, 0x00050005, 0, 100)";
                System.out.println("Query send: " + sQuery);
                stState.execute(sQuery);
                break;

            //delete char
            case 6:
                if (ku.getChars().length < 1) {
                    return;
                }
                ku.removeChar((Byte) kc_comm.get(1));
                sQuery = "DELETE FROM users_chars WHERE id=" + kc_comm.get(0) + " AND cid=" + kc_comm.get(1);
                System.out.println("Query send: " + sQuery);
                stState.execute(sQuery);
                break;


            case 8:
                sQuery = "SELECT * FROM houses WHERE id NOT IN (SELECT house_id FROM users)";
                resResult = stState.executeQuery(sQuery);
                while (resResult.next()) {
                    bb = ByteBuffer.allocate(2048);

                    bb.putInt(resResult.getInt("link_id"));
                    bb.put(getUTF(resResult.getString("map")));

                    ku.sendCommand(9, bb.array(), bb.position());
                    System.out.println("C08 send: house info");
                }

                break;
            case 10:
                sQuery = "SELECT * FROM users WHERE id=" + kc_comm.get(0);
                System.out.println("Query send: " + sQuery);
                resResult = stState.executeQuery(sQuery);
                if (!resResult.next()) {
                    return;
                }
                KamiWorldSave.saveHome(KamiCharServer.sHost, (String) kc_comm.get(2), resResult.getString("login"), (Integer) kc_comm.get(1));

                sQuery = "UPDATE users SET house_id=( SELECT id FROM houses WHERE map=\"" + (((String) kc_comm.get(2)).substring(((String) kc_comm.get(2)).lastIndexOf('/') + 1)) + "\" AND link_id=" + kc_comm.get(1) + ") WHERE id=" + kc_comm.get(0);
                System.out.println("Query send: " + sQuery);
                stState.execute(sQuery);
                break;

            //granting connection to world
            case 11:
                sQuery = "SELECT * FROM users WHERE id IN (SELECT id FROM users_chars WHERE id=" + kc_comm.get(0) + " AND cid=" + kc_comm.get(1) + ") AND login=\"" + kc_comm.get(2) + "\"";
                resResult = stState.executeQuery(sQuery);
                bb = ByteBuffer.allocate(2048);
                if (!resResult.next()) {
                    bb.put(getUTF("-1"));
                } else {
                    bb.put(getUTF(sWorldIP));
                }

                //command
                ku.sendCommand(12, bb.array(), bb.position());
                System.out.println("C12 send: redirecting to the KamiWorld");
                System.out.println("Query send: " + sQuery);

                break;

            // FLASH RESERVED COMMAND - Sending: "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>"
            case 1014001516:
                bb = ByteBuffer.allocate(4096);
                bb.put((((String) kc_comm.get(0)) + "\u0000").getBytes());
                ku.getStream().write(bb.array(), 0, bb.position());
                break;
            //
            // Unknow commands
            default:
                System.out.println("Unknow command ID: " + kc_comm.getID() + ". No Respond send");
                throw new IOException();
            //return;

        }

    //os.flush();

    }

    public KamiCommand parse(int id, java.io.DataInputStream is) throws java.io.IOException {

        KamiCommand kc = new KamiCommand();
        kc.setID(id);

        switch (id) {
            //login request
            case 1:
                kc.set(0, is.readUTF());
                kc.set(1, is.readUTF());
                break;

            //list characters
            case 3:
                kc.set(0, is.readInt());
                break;

            //add char
            case 5:
                kc.set(0, is.readInt());
                kc.set(1, is.readByte());
                kc.set(2, is.readUTF());
                kc.set(3, is.readUTF());
                kc.set(4, is.readUTF());
                break;

            //delete char
            case 6:
                kc.set(0, is.readInt());
                kc.set(1, is.readByte());
                break;

            //house listing
            case 8:
                break;
            //house pick
            case 10:
                kc.set(0, is.readInt());
                kc.set(1, is.readInt());
                kc.set(2, is.readUTF());
                break;

            //requesting connection to world
            case 11:
                kc.set(0, is.readInt());
                kc.set(1, is.readByte());
                kc.set(2, is.readUTF());
                break;

            // FLASH RESERVED COMMAND "<policy-file-request/>"
            case 1014001516:

                int codePoint = -1;
                while (codePoint != 0) {
                    codePoint = is.read();
                }
                kc.set(0, "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>");
                break;

            default:
                System.out.println("Unknow command ID: " + id);
                break;
        }

        return kc;
    }

    // =========================================================================
    // Misc.
    //
    private byte[] getUTF(String str) throws IOException {
        int strlen = str.length();
        int utflen = 0;
        int c, count = 0;

        for (int i = 0; i < strlen; i++) {
            c = str.charAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                utflen++;
            } else if (c > 0x07FF) {
                utflen += 3;
            } else {
                utflen += 2;
            }
        }

        if (utflen > 65535) {
            throw new java.io.UTFDataFormatException(
                    "encoded string too long: " + utflen + " bytes");
        }

        byte[] bytearr = new byte[utflen + 2];

        bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
        bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);

        int i = 0;
        for (i = 0; i < strlen; i++) {
            c = str.charAt(i);
            if (!((c >= 0x0001) && (c <= 0x007F))) {
                break;
            }
            bytearr[count++] = (byte) c;
        }

        for (; i < strlen; i++) {
            c = str.charAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                bytearr[count++] = (byte) c;

            } else if (c > 0x07FF) {
                bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
                bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            } else {
                bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
                bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
            }
        }

        return bytearr;
    }
}

