/*
 *  Monero Miner App (c) 2018 Uwe Post
 *  based on the XMRig Monero Miner https://github.com/xmrig/xmrig
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
// Copyright (c) 2019, Mine2Gether.com
//
// Please see the included LICENSE file for more information.

package m2g.mine2gether.androidminer;

import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.GravityCompat;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;

import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static android.os.PowerManager.PARTIAL_WAKE_LOCK;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
    private static final String LOG_TAG = "MiningSvc";
    private DrawerLayout drawer;
    boolean accepted = false;

    private final static String[] SUPPORTED_ARCHITECTURES = {"arm64-v8a", "armeabi-v7a", "x86", "x86_64"};

    private TextView tvLog;
    private TextView edStatus;
    private TextView tvMiningTo;

    private TextView tvSpeed, tvAccepted;
    private boolean validArchitecture = true;
    public static SharedPreferences preferences;

    private MiningService.MiningServiceBinder binder;

    private ScrollView svOutput;

    public static Context contextOfApplication;

    private PowerManager pm;
    private PowerManager.WakeLock wl;

    public static Context getContextOfApplication() {
        return contextOfApplication;
    }

    private Button minerBtn1, minerBtn2, minerBtn3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        preferences = getSharedPreferences(getPackageName() + "_preferences", MODE_PRIVATE);

        //PreferenceHelper.clear();

        contextOfApplication = getApplicationContext();

        if (wl != null) {
            if (wl.isHeld()) {
                wl.release();
            }
        }

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PARTIAL_WAKE_LOCK, "app:sleeplock");
        wl.acquire();

        registerReceiver(batteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

        String isshowagain = PreferenceHelper.getName("show_again");

        if (isshowagain.equals("")) {
            showdialog();
        }

        super.onCreate(savedInstanceState);

        if (PreferenceHelper.getName("address").equals("")) {
            setContentView(R.layout.activity_main);
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SettingsFragment()).commit();
        } else {
            setContentView(R.layout.activity_main);
        }

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        drawer = findViewById(R.id.drawer_layout);

        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.getMenu().getItem(0).setChecked(true);
        navigationView.setNavigationItemSelectedListener(this);

        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);

        drawer.addDrawerListener(toggle);
        toggle.syncState();

        enableButtons(false);

        // wire views
        tvLog = findViewById(R.id.output);
        tvSpeed = findViewById(R.id.speed);
        tvAccepted = findViewById(R.id.accepted);
        edStatus = findViewById(R.id.status);
        tvMiningTo = findViewById(R.id.miningTo);
        svOutput = findViewById(R.id.outputScrollView);

        minerBtn1 = (Button) findViewById(R.id.minerBtn1);
        minerBtn2 = (Button) findViewById(R.id.minerBtn2);
        minerBtn3 = (Button) findViewById(R.id.minerBtn3);

        updateUI();

        if (!Arrays.asList(SUPPORTED_ARCHITECTURES).contains(Tools.getABI())) {
            Toast.makeText(this, "Unsupported architecture, yours is " + Tools.getABI(), Toast.LENGTH_LONG).show();
            validArchitecture = false;
        }

        Intent intent = new Intent(this, MiningService.class);
        bindService(intent, serverConnection, BIND_AUTO_CREATE);
        startService(intent);


        minerBtn1.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendInput("h");
            }
        });

        minerBtn2.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendInput("p");
            }
        });

        minerBtn3.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                sendInput("r");
            }
        });

    }

    private void setStatusText(String status) {

        if (status == null || status.isEmpty()) {
            edStatus.setVisibility(View.GONE);
            edStatus.setText("");
        } else {
            edStatus.setVisibility(View.VISIBLE);
            edStatus.setText(status);
        }
    }

    public void updateUI() {

        String status = "";
        if (PreferenceHelper.getName("address").equals("")) {
            status = "Update your Wallet Address in 'Settings'";
        }

        setStatusText(status);

        String miningTo = "Mining to:";
        String pool = PreferenceHelper.getName("pool");
        String algo = PreferenceHelper.getName("algo");
        String miner = PreferenceHelper.getName("miner");

        if (pool.equals("") == false) {
            miningTo += "\n" + pool;
        }

        if (miner.equals("") == false || algo.equals("") == false) {

            miningTo += "\n";

            if (miner.equals("") == false) {
                miningTo += miner + ": ";
            }

            if (algo.equals("") == false) {
                miningTo += algo;
            }
        }

        tvMiningTo.setText(miningTo);

        if (miner.equals(Config.miner_xmrig)) {
            minerBtn1.setVisibility(View.VISIBLE);
            minerBtn2.setVisibility(View.VISIBLE);
            minerBtn3.setVisibility(View.VISIBLE);
        } else if (miner.equals(Config.miner_ninjarig)) {
            minerBtn1.setVisibility(View.VISIBLE);
            minerBtn2.setVisibility(View.VISIBLE);
            minerBtn3.setVisibility(View.VISIBLE);
        } else if (miner.equals(Config.miner_violetminer)) {
            minerBtn1.setVisibility(View.VISIBLE);
            minerBtn2.setVisibility(View.INVISIBLE);
            minerBtn3.setVisibility(View.INVISIBLE);
        } else if (miner.equals(Config.miner_xmrig_upx)) {
            minerBtn1.setVisibility(View.VISIBLE);
            minerBtn2.setVisibility(View.VISIBLE);
            minerBtn3.setVisibility(View.VISIBLE);
        } else {
            minerBtn1.setVisibility(View.INVISIBLE);
            minerBtn2.setVisibility(View.INVISIBLE);
            minerBtn3.setVisibility(View.INVISIBLE);
        }

    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.stats:
                getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new StatsFragment()).commit();
                break;
            case R.id.about:
                getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit();
                break;
            case R.id.miner: //Main view
                for (Fragment fragment : getSupportFragmentManager().getFragments()) {
                    if (fragment != null) {
                        getSupportFragmentManager().beginTransaction().remove(fragment).commit();
                    }
                }
                updateUI();
                break;
            case R.id.settings:
                getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SettingsFragment()).commit();
                break;

        }
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public void onBackPressed() {
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    private void showdialog() {
        final Dialog dialog = new Dialog(this);
        dialog.setContentView(R.layout.disclaimer);
        dialog.setTitle("Disclaimer...");
        dialog.setCancelable(false);
        Button dialogButton = (Button) dialog.findViewById(R.id.button1);
        Button exitButton = (Button) dialog.findViewById(R.id.button2);
        dialogButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                accepted = true;
                PreferenceHelper.setName("show_again", "1");
                dialog.dismiss();
            }
        });
        exitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MainActivity.this.finish();
            }
        });
        dialog.show();
    }

    private void startMining(View view) {
        if (binder == null) return;

        if (PreferenceHelper.getName("init").equals("1") == false) {
            Toast.makeText(contextOfApplication, "Save settings before mining.", Toast.LENGTH_SHORT).show();
            return;
        }

        String pool = PreferenceHelper.getName("pool");
        String pass = PreferenceHelper.getName("pass");
        String address = PreferenceHelper.getName("address");
        String algo = PreferenceHelper.getName("minerAlgo");
        String assetExtension = PreferenceHelper.getName("assetExtension");

        int cores = Integer.parseInt(PreferenceHelper.getName("cores"));
        int threads = Integer.parseInt(PreferenceHelper.getName("threads"));
        int intensity = Integer.parseInt(PreferenceHelper.getName("intensity"));

        /*
        int av = 1;

        if (Tools.getABI().contains("armeabi-v7a")) {
            av = 3;
        }
        */

        MiningService.MiningConfig cfg = binder.getService().newConfig(
                address,
                pool,
                pass,
                cores,
                threads,
                intensity,
                algo,
                assetExtension);

        binder.getService().startMining(cfg);

        updateUI();
    }

    private void stopMining(View view) {
        binder.getService().stopMining();
        updateUI();
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateUI();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    private void setMiningState(View view) {
        if (binder == null) return;
        if (binder.getService().getMiningServiceState()) {
            MainActivity.this.stopMining(view);
        } else {
            MainActivity.this.startMining(view);
        }
    }

    private void setMiningButtonState(Boolean state) {
        Button btn = findViewById(R.id.start);

        Drawable buttonDrawable = btn.getBackground();
        buttonDrawable = DrawableCompat.wrap(buttonDrawable);

        if (minerPaused) {
            btn.setText("Resume");
            DrawableCompat.setTint(buttonDrawable, Color.rgb(238, 201, 0));
            btn.setBackground(buttonDrawable);
        } else {
            if (state) {
                btn.setText("Stop");
                DrawableCompat.setTint(buttonDrawable, Color.rgb(153, 0, 0));
                btn.setBackground(buttonDrawable);
            } else {
                btn.setText("Start");
                DrawableCompat.setTint(buttonDrawable, Color.rgb(0, 153, 0));
                btn.setBackground(buttonDrawable);
            }
        }

    }

    private void appendLogOutputText(String line) {

        if (tvLog.length() > Config.logMaxLength) {
            if (binder != null) {
                tvLog.setText(binder.getService().getOutput());
            }
        } else {
            tvLog.append(line + System.lineSeparator());
        }

        svOutput.postDelayed(new Runnable() {
            @Override
            public void run() {
                svOutput.fullScroll(View.FOCUS_DOWN);
            }
        }, 50);

    }

    private ServiceConnection serverConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            binder = (MiningService.MiningServiceBinder) iBinder;
            if (validArchitecture) {
                enableButtons(true);

                findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        if (minerPaused) {
                            clearMinerLog = false;
                        }
                        minerPaused = false;
                        setMiningState(v);
                    }
                });

                setMiningButtonState(binder.getService().getMiningServiceState());

                binder.getService().setMiningServiceStateListener(new MiningService.MiningServiceStateListener() {
                    @Override
                    public void onStateChange(Boolean state) {
                        Log.i(LOG_TAG, "onMiningStateChange: " + state);
                        runOnUiThread(() -> {
                            setMiningButtonState(state);
                            if (state) {
                                if (clearMinerLog == true) {
                                    tvLog.setText("");
                                    tvAccepted.setText("0");
                                    tvSpeed.setText("0");
                                }
                                clearMinerLog = true;
                                Toast.makeText(contextOfApplication, "Miner Started", Toast.LENGTH_SHORT).show();
                            } else {
                                Toast.makeText(contextOfApplication, "Miner Stopped", Toast.LENGTH_SHORT).show();
                            }
                        });
                    }

                    @Override
                    public void onStatusChange(String status, String speed, Integer accepted) {
                        runOnUiThread(() -> {
                            appendLogOutputText(status);
                            tvAccepted.setText(Integer.toString(accepted));
                            tvSpeed.setText(speed);
                        });
                    }

                });

            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            binder = null;
            enableButtons(false);
        }
    };

    private void enableButtons(boolean enabled) {
        findViewById(R.id.start).setEnabled(enabled);
    }

    private void sendInput(String s) {
        if (binder != null) {
            binder.getService().sendInput(s);
        }
    }

    private boolean minerPaused = false;
    private boolean clearMinerLog = true;
    static boolean lastIsCharging = false;
    private BroadcastReceiver batteryInfoReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent batteryStatus) {

            int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
            boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;

            if (lastIsCharging == isCharging) return;
            lastIsCharging = isCharging;

            Toast.makeText(contextOfApplication, (isCharging ? "Device Charging" : "Device on Battery"), Toast.LENGTH_SHORT).show();

            if (PreferenceHelper.getName("pauseonbattery").equals("0") == true) {
                minerPaused = false;
                clearMinerLog = true;
                return;
            }

            boolean state = false;
            if (binder != null) {
                state = binder.getService().getMiningServiceState();
            }

            if (isCharging) {
                if (minerPaused) {
                    minerPaused = false;
                    clearMinerLog = false;
                    startMining(null);
                }
            } else {
                if (state) {
                    minerPaused = true;
                    stopMining(null);
                } else {
                    minerPaused = false;
                }
            }
        }
    };

}