package sayi.topla.mobile;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.el.ValueExpression;

import oracle.adf.model.datacontrols.device.DeviceManager;

import oracle.adf.model.datacontrols.device.DeviceManagerFactory;

import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.amx.event.ValueChangeEvent;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.framework.contract.adf.DeviceScreen;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
import oracle.adfmf.javax.faces.model.SelectItem;
import sayi.topla.application.DBConnectionFactory;

public class SayiToplamaBean {
    private boolean random = true;
    private int tableHeight;
    private int tableWidth;
    private int matris = 3;
    private int toplamPuan = 0;
    private int rekor = 64;
    private boolean kayitVar = false;
    private int anlikPuan = 0;
    private int sayilar[][] = new int[matris][matris];
    private Object temp[] = new Object[matris];
    private Integer dizi[] = new Integer[matris];
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
    private CellValue cells[][] = null;
    private Map mapList = new HashMap();
    private CellValueControl cellValueControl = null;

    public SayiToplamaBean() {
        //preferenceScope.feature.sayi.topla.SayiToplama.sayiToplamaPreference.matris


        try {
            ValueExpression ve =
                AdfmfJavaUtilities.getValueExpression("#{preferenceScope.feature.sayi.topla.SayiToplama.sayiToplamaPreference.matris}",
                                                      String.class);
            Object matrisSize = ve.getValue(AdfmfJavaUtilities.getAdfELContext());
            setMatris(Integer.parseInt(matrisSize.toString()));
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        matrisPrepair();
    }

    private void getTotalSkor() {
        Connection conn;
        try {
            conn = DBConnectionFactory.getConnection();
            String sqlQuery = "select * from SKOR";
            PreparedStatement pStmt = conn.prepareStatement(sqlQuery);
            ResultSet rs = pStmt.executeQuery();
            if (rs.next()) {
                setToplamPuan(rs.getInt("BEST_VALUE"));
                setRekor(rs.getInt("REKOR_VALUE"));
                setKayitVar(true);
            } else {
                setAnlikPuan(0);
                setRekor(64);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setSkorAndRekor() {
        Connection conn;
        try {
            conn = DBConnectionFactory.getConnection();
            if (!kayitVar) {
                String insertSQL = "Insert into SKOR (BEST_VALUE, REKOR_VALUE) values (?,?)";
                PreparedStatement pStmt = conn.prepareStatement(insertSQL);
                pStmt.setInt(1, getAnlikPuan());
                pStmt.setInt(2, getRekor());
                pStmt.execute();
            } else {
                String insertSQL = "update SKOR set BEST_VALUE=?, REKOR_VALUE=?";
                PreparedStatement pStmt = conn.prepareStatement(insertSQL);
                if (getAnlikPuan() > getToplamPuan())
                    pStmt.setInt(1, getAnlikPuan());
                else
                    pStmt.setInt(1, getToplamPuan());
                pStmt.setInt(2, getRekor());
                pStmt.execute();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void init() {
    }

    public void setPropertyChangeSupport(PropertyChangeSupport propertyChangeSupport) {
        PropertyChangeSupport oldPropertyChangeSupport = this.propertyChangeSupport;
        this.propertyChangeSupport = propertyChangeSupport;
        propertyChangeSupport.firePropertyChange("propertyChangeSupport", oldPropertyChangeSupport,
                                                 propertyChangeSupport);
    }

    public PropertyChangeSupport getPropertyChangeSupport() {
        return propertyChangeSupport;
    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }

    private boolean isEmtyCell() {
        for (int i = 0; i < matris; i++) {
            for (int j = 0; j < matris; j++) {
                if (sayilar[i][j] == 0)
                    return true;
            }
        }
        return false;
    }

    private void randomSayiAtama() {
        Random r = new Random();
        while (true) {
            int i = r.nextInt(matris);
            int j = r.nextInt(matris);
            if (cells[i][j].getValue() == 0 && getRekor() < 512) {
                cells[i][j].setValue(2);
                break;
            } else if(cells[i][j].getValue() == 0 && getRekor() >= 512) {
                cells[i][j].setValue(ikiUzeriSayiUret(1+r.nextInt(2)));
                break;
            }
        }
    }

    /**
     * 2^x
     * */
    private int ikiUzeriSayiUret(int x) {
        int sayi = 1;
        for (int i = 0; i < x; i++) {
            sayi=sayi*2;
        }
        return sayi;
    }

    public void up(ActionEvent actionEvent) {
        random = false;
        cellValueControl.setYasla(false);
        cellValueControl.setCells(cells);
        for (int rowIndex = 0; rowIndex < matris; rowIndex++) {
            //goUp(rowIndex);
            cellValueControl.goUp(rowIndex);
        }
        if (cellValueControl.isYasla())
            randomSayiAtama();
        setCells(cellValueControl.getCells());
        setSayilar(sayilar);
        setAnlikPuan(cellValueControl.getCurrentToplam());
        ekraniHazirla();
        boolean isGameOver = cellValueControl.isGameOver(cells);
        if (!isGameOver)
            onQueueC3ButtontAction();
        AdfmfJavaUtilities.flushDataChangeEvent();
    }

    private void onQueueC3ButtontAction() {
        setSkorAndRekor();
        AdfmfContainerUtilities.invokeContainerJavaScriptFunction(AdfmfJavaUtilities.getFeatureName(),
                                                                  "adf.mf.api.amx.doNavigation",
                                                                  new Object[] { "goGameOver" });
    }

    public void down(ActionEvent actionEvent) {
        random = false;
        cellValueControl.setYasla(false);
        cellValueControl.setCells(cells);
        for (int rowIndex = 0; rowIndex < matris; rowIndex++) {
            //goDown(rowIndex);
            cellValueControl.goDown(rowIndex);
        }
        if (cellValueControl.isYasla())
            randomSayiAtama();
        setCells(cellValueControl.getCells());
        setSayilar(sayilar);
        setAnlikPuan(cellValueControl.getCurrentToplam());
        ekraniHazirla();

        boolean isGameOver = cellValueControl.isGameOver(cells);
        if (!isGameOver)
            onQueueC3ButtontAction();
        AdfmfJavaUtilities.flushDataChangeEvent();
    }

    public void right(ActionEvent actionEvent) {
        random = false;
        cellValueControl.setYasla(false);
        cellValueControl.setCells(cells);
        for (int rowIndex = 0; rowIndex < matris; rowIndex++) {
            //goRight(rowIndex);
            cellValueControl.goRight(rowIndex);
        }
        if (cellValueControl.isYasla())
            randomSayiAtama();
        setCells(cellValueControl.getCells());
        setSayilar(sayilar);
        setAnlikPuan(cellValueControl.getCurrentToplam());
        ekraniHazirla();
        boolean isGameOver = cellValueControl.isGameOver(cells);
        if (!isGameOver)
            onQueueC3ButtontAction();
        AdfmfJavaUtilities.flushDataChangeEvent();
    }

    public void left(ActionEvent actionEvent) {
        random = false;
        cellValueControl.setYasla(false);
        cellValueControl.setCells(cells);
        for (int rowIndex = 0; rowIndex < matris; rowIndex++) {
            //goLeft(rowIndex);
            cellValueControl.goLeft(rowIndex);
        }
        if (cellValueControl.isYasla())
            randomSayiAtama();
        setCells(cellValueControl.getCells());
        setSayilar(sayilar);
        setAnlikPuan(cellValueControl.getCurrentToplam());
        ekraniHazirla();
        boolean isGameOver = cellValueControl.isGameOver(cells);
        if (!isGameOver)
            onQueueC3ButtontAction();


        AdfmfJavaUtilities.flushDataChangeEvent();
    }


    private void toplamKontrolL(int rowIndex, int b_index, int b_value) {
        int sayac = b_index + 1;
        while (sayac < matris) {
            int sayac_value = sayilar[rowIndex][sayac];
            if (sayac_value == 0) {
                sayac++;
                continue;
            } else if (b_value == sayac_value) {
                sayilar[rowIndex][b_index] = sayac_value * 2;
                sayilar[rowIndex][sayac] = 0;
                if (sayac < matris) {
                    b_index = sayac;
                    b_value = sayilar[rowIndex][b_index];
                }
                sayac++;
            } else {
                b_value = sayilar[rowIndex][sayac];
                b_index = sayac;
                sayac++;
            }
        }
    }

    private void toplamKontrolR(int rowIndex, int b_index, int b_value) {
        int sayac = b_index - 1;
        while (sayac >= 0) {
            int sayac_value = sayilar[rowIndex][sayac];
            if (sayac_value == 0) {
                sayac--;
                continue;
            } else if (b_value == sayac_value) {
                sayilar[rowIndex][b_index] = sayac_value * 2;
                sayilar[rowIndex][sayac] = 0;
                if (sayac != -1 && sayac < matris) {
                    b_index = sayac;
                    b_value = sayilar[rowIndex][b_index];
                }
                sayac--;
            } else {
                b_value = sayilar[rowIndex][sayac];
                b_index = sayac;
                sayac--;
            }
        }
    }

    private void toplamKontrolDown(int rowIndex, int b_index, int b_value) {
        int sayac = b_index - 1;
        while (sayac >= 0) {
            int sayac_value = sayilar[sayac][rowIndex];
            if (sayac_value == 0) {
                sayac--;
                continue;
            } else if (b_value == sayac_value) {
                sayilar[b_index][rowIndex] = sayac_value * 2;
                sayilar[sayac][rowIndex] = 0;
                if (sayac != -1 && sayac < matris) {
                    b_index = sayac;
                    b_value = sayilar[b_index][rowIndex];
                }
                sayac--;
            } else {
                b_value = sayilar[sayac][rowIndex];
                b_index = sayac;
                sayac--;
            }
        }
    }

    private void toplamKontrolUp(int rowIndex, int b_index, int b_value) {
        int sayac = b_index + 1;
        while (sayac < matris) {
            int sayac_value = sayilar[sayac][rowIndex];
            if (sayac_value == 0) {
                sayac++;
                continue;
            } else if (b_value == sayac_value) {
                sayilar[b_index][rowIndex] = sayac_value * 2;
                sayilar[sayac][rowIndex] = 0;
                if (sayac != -1 && sayac < matris) {
                    b_index = sayac;
                    b_value = sayilar[b_index][rowIndex];
                }
                sayac++;
            } else {
                b_value = sayilar[sayac][rowIndex];
                b_index = sayac;
                sayac++;
            }
        }
    }

    private void reTainAllRowLeft(Map sirala, int rowIndex) {
        Iterator iterator = sirala.entrySet().iterator();
        int i = 0;
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            Integer value = new Integer(entry.getValue().toString());
            sayilar[rowIndex][i] = value.intValue();
            i++;
        }
        while (i < matris) {
            sayilar[rowIndex][i] = 0;
            i++;
        }
    }

    private void reTainAllRowUp(Map sirala, int rowIndex) {
        Iterator iterator = sirala.entrySet().iterator();
        int i = 0;
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            Integer value = new Integer(entry.getValue().toString());
            sayilar[i][rowIndex] = value.intValue();
            i++;
        }
        while (i < matris) {
            sayilar[i][rowIndex] = 0;
            i++;
        }
    }


    private void goRight(int rowIndex) {
        int b_index = 0, b_value = 0;
        for (int i = matris; i > 0; i--) {
            b_index = i - 1;
            b_value = sayilar[rowIndex][b_index];
            toplamKontrolR(rowIndex, b_index, b_value);
        }

        Map m = new HashMap();
        for (int i = 0; i < matris; i++) {
            if (sayilar[rowIndex][i] != 0)
                m.put(new Integer(i), new Integer(sayilar[rowIndex][i]));
        }
        reTainAllRowRight(m, rowIndex);
    }

    private void goUp(int rowIndex) {
        int b_index = 0, b_value = 0;
        int dizi[] = new int[matris];
        for (int j = 0; j < matris; j++)
            dizi[j] = sayilar[j][rowIndex];
        for (int i = 0; i < matris; i++) {
            b_index = i;
            b_value = sayilar[b_index][rowIndex];
            toplamKontrolUp(rowIndex, b_index, b_value);
        }

        Map m = new HashMap();
        for (int i = 0; i < matris; i++) {
            if (sayilar[i][rowIndex] != 0)
                m.put(new Integer(i), new Integer(sayilar[i][rowIndex]));
        }
        reTainAllRowUp(m, rowIndex);
    }

    private void goLeft(int rowIndex) {
        int b_index = 0, b_value = 0;
        int dizi[] = new int[matris];
        for (int j = 0; j < matris; j++)
            dizi[j] = sayilar[j][rowIndex];
        for (int i = 0; i < matris; i++) {
            b_index = i;
            b_value = sayilar[rowIndex][b_index];
            toplamKontrolL(rowIndex, b_index, b_value);
        }

        Map m = new HashMap();
        for (int i = 0; i < matris; i++) {
            if (sayilar[rowIndex][i] != 0)
                m.put(new Integer(i), new Integer(sayilar[rowIndex][i]));
        }
        reTainAllRowLeft(m, rowIndex);
    }

    private void goDown(int rowIndex) {
        int b_index = 0, b_value = 0;
        int dizi[] = new int[matris];
        for (int j = 0; j < matris; j++)
            dizi[j] = sayilar[j][rowIndex];
        for (int i = matris; i > 0; i--) {
            b_index = i - 1;
            b_value = sayilar[b_index][rowIndex];
            toplamKontrolDown(rowIndex, b_index, b_value);
        }

        Map m = new HashMap();
        for (int i = 0; i < matris; i++) {
            if (sayilar[i][rowIndex] != 0)
                m.put(new Integer(i), new Integer(sayilar[i][rowIndex]));
        }
        reTainAllRowDown(m, rowIndex);
    }

    private void reTainAllRowRight(Map sirala, int rowIndex) {
        Iterator iterator = sirala.entrySet().iterator();
        int i = 0;
        int dizi[] = new int[sirala.size()];
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            Integer value = new Integer(entry.getValue().toString());
            dizi[i] = value.intValue();
            i++;
        }
        i = 1;
        while (i <= dizi.length) {
            sayilar[rowIndex][matris - i] = dizi[dizi.length - i];
            i++;
        }
        while (i <= matris) {
            sayilar[rowIndex][matris - i] = 0;
            i++;
        }
    }

    private void reTainAllRowDown(Map sirala, int rowIndex) {
        Iterator iterator = sirala.entrySet().iterator();
        int i = 0;
        int dizi[] = new int[sirala.size()];
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry)iterator.next();
            Integer value = new Integer(entry.getValue().toString());
            dizi[i] = value.intValue();
            i++;
        }
        i = 1;
        while (i <= dizi.length) {
            sayilar[matris - i][rowIndex] = dizi[dizi.length - i];
            i++;
        }
        while (i <= matris) {
            sayilar[matris - i][rowIndex] = 0;
            i++;
        }
    }


    public void setSayilar(int[][] sayilar) {
        int[][] oldOptions = this.sayilar;
        this.sayilar = sayilar;
        propertyChangeSupport.firePropertyChange("sayilar", oldOptions, sayilar);
    }

    public int[][] getSayilar() {
        return sayilar;
    }

    public void setMatris(int matris) {
        int oldOptions = this.matris;
        this.matris = matris;
        propertyChangeSupport.firePropertyChange("matris", oldOptions, matris);
    }

    public int getMatris() {
        return matris;
    }

    public void matrisSelection(ValueChangeEvent valueChangeEvent) {
        Object object = valueChangeEvent.getNewValue();
        if (object != null) {
            setMatris(new Integer(object.toString()).intValue());
            matrisPrepair();
            AdfmfJavaUtilities.flushDataChangeEvent();
        }
    }

    private void matrisPrepair() {

        DeviceManager ds = DeviceManagerFactory.getDeviceManager();
        setTableHeight(ds.getScreenHeight());
        setTableWidth(ds.getScreenWidth());
        sayilar = new int[matris][matris];
        cells = new CellValue[matris][matris];
        Random r = new Random();
        int i1, i2, i3, i4;
        while (true) {
            i1 = r.nextInt(matris);
            i2 = r.nextInt(matris);
            i3 = r.nextInt(matris);
            i4 = r.nextInt(matris);
            if (i1 != i3 && i2 != i4)
                break;
        }
        sayilar[i1][i2] = 2;
        sayilar[i3][i4] = 2;
        String height = "";
        String widht = "";
        if (getTableHeight() >= getTableWidth()) {
            height = ((getTableWidth()) * 3 / 4) / getMatris() + "px;";
            widht = ((getTableWidth()) * 3 / 4) / getMatris() + "px;";
        } else {
            height = (getTableHeight() * 3 / 4) / getMatris() + "px;";
            widht = (getTableHeight() * 3 / 4) / getMatris() + "px;";
        }

        cells[i1][i2] = new CellValue(2, height, widht);
        cells[i3][i4] = new CellValue(2, height, widht);
        for (int i = 0; i < matris; i++) {
            for (int j = 0; j < matris; j++) {
                if (cells[i][j] != null && cells[i][j].getValue() != 0) {
                    continue;
                }
                cells[i][j] = new CellValue(0, height, widht);
            }
        }


        Integer[] dizi = new Integer[matris];
        for (int i = 0; i < matris; i++)
            dizi[i] = new Integer(i);
        setDizi(dizi);
        setAnlikPuan(0);
        getTotalSkor();
        setSayilar(sayilar);
        cellValueControl = new CellValueControl(cells);
        ekraniHazirla();
        setCells(cells);
    }

    private void ekraniHazirla() {
        Object tempArray[] = new Object[matris];
        int enbuyukDeger = 0;
        CellValue row[] = null;
        for (int i = 0; i < matris; i++) {
            row = new CellValue[matris];
            for (int j = 0; j < matris; j++) {
                if (cells[i][j].getValue() >= enbuyukDeger)
                    enbuyukDeger = cells[i][j].getValue();
                if (cells[i][j] != null && cells[i][j].getValue() != 0) {
                    row[j] = cells[i][j];
                    continue;
                }
                row[j] = cells[i][j];
            }
            System.out.println();
            tempArray[i] = row;
        }
        setTemp(tempArray);
        if (enbuyukDeger >= rekor) {
            setRekor(getRekor() * 2);
            setAnlikPuan(getAnlikPuan() + getRekor());
        }
    }

    public String goCreateNewGame() {
        matrisPrepair();
        return "newGame";
    }

    public String goReturnGame() {
        return "return_game";
    }

    public Object[] getMapToArray() {
        return getMapList().entrySet().toArray();
    }


    public Integer[] getDizi() {
        return dizi;
    }

    public void setDizi(Integer[] dizi) {
        Integer[] oldOptions = this.dizi;
        this.dizi = dizi;
        propertyChangeSupport.firePropertyChange("dizi", oldOptions, dizi);
    }

    public void setCells(CellValue[][] cells) {
        CellValue[][] oldOptions = this.cells;
        this.cells = cells;
        propertyChangeSupport.firePropertyChange("cells", oldOptions, cells);
    }

    public CellValue[][] getCells() {
        return cells;
    }

    public void setTemp(Object[] temp) {
        Object[] oldTemp = this.temp;
        this.temp = temp;
        propertyChangeSupport.firePropertyChange("temp", oldTemp, temp);
    }

    public Object[] getTemp() {
        return temp;
    }

    public void setMapList(Map mapList) {
        Map oldMapList = this.mapList;
        this.mapList = mapList;
        propertyChangeSupport.firePropertyChange("mapList", oldMapList, mapList);
    }

    public Map getMapList() {
        return mapList;
    }

    public void setTableHeight(int tableHeight) {
        int oldTableHeight = this.tableHeight;
        this.tableHeight = tableHeight;
        propertyChangeSupport.firePropertyChange("tableHeight", oldTableHeight, tableHeight);
    }

    public int getTableHeight() {
        return tableHeight;
    }

    public void setTableWidth(int tableWidth) {
        int oldTableWidth = this.tableWidth;
        this.tableWidth = tableWidth;
        propertyChangeSupport.firePropertyChange("tableWidth", oldTableWidth, tableWidth);
    }

    public int getTableWidth() {
        return tableWidth;
    }

    public void setToplamPuan(int toplamPuan) {
        int oldToplamPuan = this.toplamPuan;
        this.toplamPuan = toplamPuan;
        propertyChangeSupport.firePropertyChange("toplamPuan", oldToplamPuan, toplamPuan);
    }

    public int getToplamPuan() {
        return toplamPuan;
    }

    public void setRekor(int rekor) {
        int oldRekor = this.rekor;
        this.rekor = rekor;
        propertyChangeSupport.firePropertyChange("rekor", oldRekor, rekor);
    }

    public int getRekor() {
        return rekor;
    }

    public void setAnlikPuan(int anlikPuan) {
        int oldAnlikPuan = this.anlikPuan;
        this.anlikPuan = anlikPuan;
        propertyChangeSupport.firePropertyChange("anlikPuan", oldAnlikPuan, anlikPuan);
    }

    public int getAnlikPuan() {
        return anlikPuan;
    }

    public void yeniOyun(ActionEvent actionEvent) {
        matrisPrepair();
    }

    public void setKayitVar(boolean kayitVar) {
        boolean oldKayitVar = this.kayitVar;
        this.kayitVar = kayitVar;
        propertyChangeSupport.firePropertyChange("kayitVar", oldKayitVar, kayitVar);
    }

    public boolean isKayitVar() {
        return kayitVar;
    }

    public void shared(ActionEvent actionEvent) {
          
    }
}
