//i450
//Zsomb Istvn
//12. vfolyam
//Pcsi Lewey Klra Gimnzium
//zsombo8774@gmail.com
//Android Studio 2.3.3
//Java Runtime Environment 1.8.0
//Kompatibilits: Android 4.1 Jellybean - API 16 vagy brmely magasabb
package user.komal_i450;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import java.util.Random;
import android.os.Handler;

public class MainActivity extends AppCompatActivity {
//A program indulsakor meghvom a betoltes() metdust
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        betoltes();
    }
//Rajzolshoz szksges llandk
    final int meret = 100;
    final int DELAY = 30;
    Paint myPaint = new Paint();
//Az oszlopokat jelent gombok ID gyjtemnye
    int[] azonositok = new int[]{R.id.n1,R.id.m1,R.id.n2,R.id.m2,R.id.e1,R.id.e2};
//Meghatrozom, melyik gomb lenyomsa melyik metdust hvja majd meg
//Meghvom a startup() s segitseg() metdusokat.
    void betoltes(){
        for (int j = 0; j < 6; j += 1){
            final int i = j;
            findViewById(azonositok[i]).setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if (mozgathato && (motionEvent.getAction() == MotionEvent.ACTION_DOWN)) {
                        if (motionEvent.getY() > view.getHeight() / 2) {
                            felhuz(i);
                        } else {
                            lehuz(i);
                        }
                        ellenoriz();
                    }
                    return false;
                }
            });
        }
        findViewById(R.id.ujra).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == motionEvent.ACTION_DOWN){ujjatek();}
                return false;}
        });
        findViewById(R.id.sorok).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == motionEvent.ACTION_DOWN){sorvalto();}
                return false;}
        });
        findViewById(R.id.help).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == motionEvent.ACTION_DOWN){segitseg();}
                return false;}
        });
        findViewById(R.id.felad).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == motionEvent.ACTION_DOWN){feladas();}
                return false;}
        });
        findViewById(R.id.adatok).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == motionEvent.ACTION_DOWN){adatok();}
                return false;}
        });
        myPaint.setTextSize(meret * 9 / 10);
        myPaint.setTypeface(Typeface.create("Arial", Typeface.BOLD));
        startup();
        segitseg();
    }
//A tabla[][] 6 szles s olyan magas ahny sort kezelnem kell. Trolja a megjelentend szmjegyeket,
//valamint a 2. s 4. oszlopban a mveleti jelekhez rendelt szmokat, melyek:
//1:+ 2:- 3:* 4:/ s -1:< 0:= +1:>
    int[][] tabla;
//A csuszas[6] trolja melyik oszlopot hnyszor cssztattam le (+) avagy fel (-)
    int[] csuszas;
    int sorok = 4;
//mozgathato a felttele annak, hogy a jtkos cssztathassa az oszlopokat.
    boolean mozgathato = false;
//Nullzom a tabla[][] s oszlop[] tartalmt, megkezdem egy j, helyes kezdllapot generlst (general), majd sszekeverem azt.
//Ha vletlen egy helyes megolds kerlne a kpernyre, jra futtatom a metdust.
//R.id.ujra is meghvhatja.
    void startup() {
        tabla = new int[sorok][6];
        csuszas = new int[]{0,0,0,0,0,0};
        general();
        for (int oszlop = 0; oszlop < 6; oszlop += 1){
            ujrasorsol(oszlop);
            rajzol(oszlop, 0);
        }
        if (mindjo()){
            startup();}else{mozgathato = true;}
    }
//lehuz() s felhuz() metdusokat az oszlopokat jelent gombok hvjk meg.
//Az adott oszlop tartalmt a bemenetnek megfelelen fel vagy le mozgatom, a kies rsz megjelenik a megjelen rszen termszetesen.
//Meghvom a rajzol() metdust a mozgats irnynak megfelel haladas paramterrel.
    void lehuz(int oszlop) {
        if (!animal[oszlop]) {
            int kezdo = tabla[0][oszlop];
            for (int i = 0; i < sorok - 1; i += 1) {
                tabla[i][oszlop] = tabla[i + 1][oszlop];
            }
            tabla[sorok - 1][oszlop] = kezdo;
            rajzol(oszlop, +1);
            csuszas[oszlop] += 1;
        }
    }
    void felhuz(int oszlop) {
        if (!animal[oszlop]) {
            int kezdo = tabla[sorok - 1][oszlop];
            for (int i = sorok - 2; i >= 0; i -= 1) {
                tabla[i + 1][oszlop] = tabla[i][oszlop];
            }
            tabla[0][oszlop] = kezdo;
            rajzol(oszlop, -1);
            csuszas[oszlop] -= 1;
        }
    }
    Handler myHandler = new Handler();
//Eljelfggvny.
    public int sgn(double a){if(a>0){return 1;}else{if(a<0){return -1;}else{return 0;}}}
//Kiszmolja az els kt szmjegyen a kztk lv mveleti jellel vgzett mvelet eredmnyt.
    public double muvelet(int n1, int m1, int n2){
        switch (m1) {
            case 1:
                return n1 + n2;
            case 2:
                return n1 - n2;
            case 3:
                return n1 * n2;
            default:
                return (double) n1 / (double) n2;
        }
    }
//Meghatrozza, hogy a tabla[][] egyik sorban helyes-e a relci.
    public boolean helyes(int n1, int m1, int n2, int m2, int e1, int e2) {
        return (sgn(muvelet(n1,m1,n2) - (10*e1+e2)) == m2);
    }
//Meghatrozza azt a legkisebb nemnegatv egszt, mellyel A kongruens modulo B.
    public int mod(int a, int b){ //a mod b
        int m = a % b;
        if (m >= 0) { return m; } else { return m + b; }
    }
//Keresi a tblzatban a hibs sort. Ha nincs, akkor minden sor helyes, teht a jtkos megoldotta a feladvnyt.
    public boolean mindjo(){
        boolean megjo = true;
        for (int i = 0; (i < sorok ) && megjo; i += 1){
            megjo = helyes(tabla[i][0],tabla[i][1],tabla[i][2],tabla[i][3],tabla[i][4],tabla[i][5]);
        }
        return megjo;
    }
//A jtkos minden lpse meghvja az ellenoriz() metdust. Vizsglja, hogy megoldotta-e a jtkos a feladvnyt.
    void ellenoriz(){
        if (mindjo()){
            mozgathato = false;
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Gratullok!");
            builder.setMessage("Feladvny megoldva, minden sorban helyes a relci!");
            builder.setPositiveButton("HURR!",null);
            builder.show();
        }
    }
//Egy vletlen egsz szmot ad [min,max] zrt-zrt intervallumbl.
    public int rsz(int min, int max){
        Random r = new Random();
        return min + r.nextInt(max-min+1);
    }
//Vletlenszeren valamennyivel elcssztat egy bizonyos oszlopot. A helyes kezdllapot legenerlsa utn hasznlom annak megkevershez.
    void ujrasorsol(int oszlop){
        int[] masolat = new int[sorok];
        for (int i = 0; i < sorok; i += 1){masolat[i] = tabla[i][oszlop];}
        int r = rsz(0,127);
        for (int i = 0; i < sorok; i += 1){tabla[i][oszlop] = masolat[mod((i + r), sorok)];}
        csuszas[oszlop] += mod(r, sorok);
    }
//Vletlenszeren meghatrozom az els kt szmjegyet s a kztk lv mveleti jelet.
//Amennyiben az eredmny (utols kt oszlop) gy lehet pozitv egsz, 1/2 esllyel egyenlsget ksztek, klnben:
//1/5 esllyel egy valsznleg nagyobb, klnben egy valsznbben kisebb eredmny ksztek, s meghatrozom a megfelel relcit.
    void general(){
        for (int i = 0; i < sorok; i += 1){
            int n1 = rsz(1,9);
            int n2 = rsz(1,9);
            int m1 = rsz(1,4);
            double ered = muvelet(n1,m1,n2);
            if((ered == Math.floor(ered)) && ered > 0 && rsz(1,2)==1)
            {
                tabla[i][0] = n1;
                tabla[i][1] = m1;
                tabla[i][2] = n2;
                tabla[i][3] = 0;
                tabla[i][4] = (int)(Math.floor(ered / 10));
                tabla[i][5] = mod((int)Math.floor(ered), 10);
            }
            else
            {
                int e1;
                if (rsz(1,5)==1){e1 = rsz(0, 9);}else{e1 = rsz(0,(int)(Math.ceil(ered / 10)));}
                    int e2 = rsz(0, 9);
                    tabla[i][0] = n1;
                    tabla[i][1] = m1;
                    tabla[i][2] = n2;
                    tabla[i][3] = sgn(ered - (10 * e1 + e2));
                    tabla[i][4] = e1;
                    tabla[i][5] = e2;
            }
        }
    }
//Az R.id.sorok gomb hvja meg, ezzel vltoztathat a sorok szma.
    void sorvalto(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        LinearLayout linearLayout = new LinearLayout(this);
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        final SeekBar seekBar = new SeekBar(this);
        seekBar.setMax(7);
        seekBar.setProgress(sorok-3);
        final TextView textView = new TextView(this);
        TextViewCompat.setTextAppearance(textView,R.style.TextAppearance_AppCompat_Title);
        textView.setText("Sorok szma : " + sorok);
        SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
            @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                textView.setText("Sorok szma: " + String.valueOf(seekBar.getProgress() + 3));}
            @Override public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override public void onStopTrackingTouch(SeekBar seekBar) {}};
        seekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);
        builder.setPositiveButton("VLTOZTAT", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
             if ((seekBar.getProgress() + 3) != sorok) {sorok = seekBar.getProgress() + 3; startup();}
            }});

        builder.setTitle("");
        linearLayout.addView(textView);
        linearLayout.addView(seekBar);


        builder.setView(linearLayout);
        builder.show();

    }
//A jtk indtsakor jelenik meg, tovbb az R.id.help gomb hvhatja meg. Megjelenti a jtkszablyokat.
    void segitseg(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Segtsg");
        builder.setMessage("Az oszlopok fels vagy als felbe kattintva azok minden eleme mozgathat fel vagy le eggyel. \n" +
                "A jtk clja, hogy minden sorban helyes legyen a mvelet. \n" +
                "Az oldalt lv gombokkal kezdhet j jtk, vltoztathat a sorok szma, vagy adhat fel a jtk. \n\n" +
                "J jtkot!");
        builder.setPositiveButton("RTEM", null);
        builder.show();
    }
//R.id.felad hvja meg, a jtkosnak lehetsge nylik feladni a jtkot, ekkor minden oszlopra meghvom a huzamignemjo() metdust, ezzel ltvnyosan megoldva a feladvnyt.
//(gy a jtkos megbizonyosodhat rla, hogy a feladvny valban megoldhat volt az oszlopokat cssztatva, hiszen lthatja a megolds menett.)
    void feladas(){
        if(mozgathato){
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Biztosan feladod?");
            builder.setMessage("Amennyiben igen, a feladvny megoldsa lesz lthat.");
            builder.setNegativeButton("MGSEM", null);
            builder.setPositiveButton("Igen, feladom.", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    mozgathato = false;
                    for (int oszlop = 0; oszlop < 6; oszlop += 1) {
                        huzamignemjo(oszlop);
                        }
                    }
            });
            builder.show();
        }
    }
//R.id.ujra hvja meg, elfogadskor startup() j jtk kezddik.
    void ujjatek(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Szeretnl egy j jtkot kezdeni?");
        builder.setPositiveButton("IGEN", new DialogInterface.OnClickListener() {
            @Override public void onClick(DialogInterface dialogInterface, int i) {
                startup();}});
        builder.setNegativeButton("MGSEM",null);
        builder.show();
    }
//Addig hvja meg egy bizonyos oszlop felhuz() metdust, mg az oszlop elemei az eredetileg helyesnek generlt helyre nem kerlnek.
    void huzamignemjo(final int oszlop){
        felhuz(oszlop);
        if (mod(csuszas[oszlop],sorok) != 0){
        myHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                huzamignemjo(oszlop);
            }
        },3*DELAY);
    }
    }
//animal[] trolja, hogy ppen mozog-e egy bizonyos oszlop.
//Az animci befejeztig nem mozgathat ugyanazon oszlop a programbli hibk kikszblse rdekben.
    boolean[] animal = new boolean[]{false,false,false,false,false,false};
//Egy bizonyos oszlop megjelentsrt felels algoritmus.
//A haladas paramter eljele megadja, hogy fel- vagy lefel cssztattam az oszlopot. Kezdeti rtke -1, 0 vagy +1.
//0 halads esetn az algoritmus lell, hisz nem kell mozgatni az oszlopokat, klnben:
//DELAY-nyi id elteltvel jra meghvja magt, immr egy, a -10 vagy +10-hez 1-gyel kzelebbi haladas paramterrel.
//A haladas paramter abszoltrtke megadja, hogy a cssztats eltti llapothoz kpes hny tizedet haladt az animci az azutni llapot fel.
//Amint a haladas elri a +-10-et, lell az animci, s az adott oszlop jra cssztathat a jtkos szmra.
    void rajzol(final int oszlop, final int haladas) {
        Bitmap bmp = Bitmap.createBitmap(meret, sorok * meret, Bitmap.Config.ARGB_8888);
        Canvas g = new Canvas(bmp);
        animal[oszlop] = true;
        for (int i = -1; i < sorok + 1; i +=1){
            String ki;
            int q = mod(i - sgn(haladas), sorok);
            switch(oszlop){
                case 1 : ki = new String[]{"+","-","*",""}[tabla[q][oszlop]-1]; break;
                case 3 : ki = new String[]{"<","=",">"}[tabla[q][oszlop]+1]; break;
                default : ki = String.valueOf(tabla[q][oszlop]);}
            g.drawText(ki,20,
                    meret * ( i + (float)0.99 - (float)haladas / (float)10 )
                    , myPaint);
        }
        if (mod(haladas,10) != 0){
            myHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    rajzol(oszlop,haladas+sgn(haladas));
                }
            },DELAY);}
        else {animal[oszlop] = false;}
        //else{mozgathato=true;}

        ImageButton btn=(ImageButton)findViewById(azonositok[oszlop]);
        btn.setImageBitmap(bmp);
    }
//R.id.adatok hvja meg. A feladat adatait s engem tartalmaz.
    void adatok(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Adatok");
        builder.setMessage("i450 \n" +
                "Zsomb Istvn \n" +
                "12. vfolyam \n" +
                "Pcsi Lewey Klra Gimnzium \n" +
                "zsombo8774@gmail.com \n" +
                "Android Studio 2.3.3 \n" +
                "JRE 1.8.0 \n" +
                "Android 4.1 Jellybean - API 16");
        builder.show();
    }
}