package com.hyperling.apps.games;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.text.TextPaint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;

/**
 * Created by ling on 12/17/16.
 * https://youtu.be/-XOMJYZmfkw?list=PLWweaDaGRHjvQlpLV0yZDmRKVBdy6rSlg
 */

public abstract class GameView extends SurfaceView implements SurfaceHolder.Callback{

    public static final int WIDTH = 640;
    public static final int HEIGHT = 400;

    protected Resources resources;
    protected final String sharedPreferencesKey, higherQualityKey, fpsKey;

    protected static String TAG;

    protected SharedPreferences sharedPreferences;
    protected boolean higherQualityEnabled, fpsEnabled;

    protected int gameSpeed = -5;
    protected int boostQty;
    protected long boostEnd;
    protected boolean boosting;

    protected GameLoopThread thread;
    protected GameBackground background, clouds, lava;

    protected TextPaint textPaint;

    public GameView(Context context){
        super(context);

        // For filling strings and getting Bitmaps
        resources = getResources();

        // Keys
        sharedPreferencesKey = resources.getString(R.string.sharedPreferencesKey);
        higherQualityKey = resources.getString(R.string.higherQualityKey);
        fpsKey = resources.getString(R.string.fpsKey);

        // Initialize shared preferences
        sharedPreferences = context.getSharedPreferences(sharedPreferencesKey, Context.MODE_PRIVATE);
        higherQualityEnabled = sharedPreferences.getBoolean(higherQualityKey, false);
        fpsEnabled = sharedPreferences.getBoolean(fpsKey, false);

        // For output
        TAG = resources.getString(R.string.TAG);

        // Add the callback to SurfaceHolder (This allows control of events)
        getHolder().addCallback(this);

        // Initialize engine
        thread = new GameLoopThread(getHolder(), this);
    }

    protected static String getTAG() {
        return TAG;
    }

    protected void boost(int boostMultiplier, long boostDuration){
        if (!boosting){
            boosting = true;
            boostQty = boostMultiplier;
            boostEnd = System.currentTimeMillis() + boostDuration;

            gameSpeed *= boostQty;
        }
    }

    protected void setGameSpeed(int newSpeed){
        gameSpeed = newSpeed;
    }

    protected int findPlatformY(Player player, ArrayList<Platform> platforms){

        // Get the tallest (smallest) platform.y where platform.y < player.y
        int platformHighestY = HEIGHT*2;
        for (Platform platform : platforms){

            if (player.endX > platform.x &&
                    player.x < platform.endX &&
                    player.centerY <= platform.y &&
                    platform.y < platformHighestY){
                Log.d(TAG, "GameView.findPlatformY():" +
                        "  player.x=" + player.x +
                        ", player.endX=" + player.endX +
                        ", player.centerY=" + player.centerY +
                        ", platform.x=" + platform.x +
                        ", platform.endX=" + platform.endX +
                        ", platform.y=" + platform.y +
                        ", platformHighestY=" + platformHighestY);

                platformHighestY = platform.y;
            }
        }

        Log.d(TAG, "GameView.findPlatformY():  player.y=" + player.y + ", platformHighestY=" + platformHighestY);
        return platformHighestY;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // Safe to start the thread
        textPaint = new TextPaint();
        textPaint.setTextSize(textPaint.getTextSize() * 2);

        thread.setRunning(true);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Try to stop the thread
        boolean retry = true;
        int retryCount = 0;
        while(retry && retryCount < 1000){
            try{
                thread.setRunning(false);
                thread.join();
                thread = null;
                retry = false;
            } catch(Exception e){
                e.printStackTrace();
                retryCount++;
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    protected void pauseGame(String scoreKey, int score){
        // Save and force a commit
        saveScore(scoreKey, score);
        sharedPreferences.edit().commit();

        System.exit(1);
    }

    protected void saveScore(String scoreKey, int score){
            // Check if score is better than high score
            int oldScore = sharedPreferences.getInt(scoreKey, 0);
            Log.d(TAG, "GameView.saveScore():  score=" + score + ", oldScore=" + oldScore);

            if (score > oldScore) {
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putInt(scoreKey, score);
                editor.apply();
            }

            int highScore = sharedPreferences.getInt(scoreKey, 0);
            Log.d(TAG, "GameView.saveScore():  Saved, new highScore=" + highScore);
    }

    protected void update(){
        // Check if the boost is over and end it
        if (boosting && System.currentTimeMillis() > boostEnd){
            boosting = false;
            gameSpeed /= boostQty;
        }
    }

    @Override
    public void draw(Canvas canvas) {

        if (canvas != null) {
            super.draw(canvas);
            /*
            final float scaleX = (float) getWidth()/WIDTH;
            final float scaleY = (float) getHeight()/HEIGHT;
            Log.d(TAG, "GameView.draw():  Canvas not null, scaling! scaleX=" + scaleX + ", scaleY=" + scaleY);
            Log.d(TAG, "GameView.draw():  Canvas not null, scaling! getScaleX()=" + getScaleX() + ", getScaleY()=" + getScaleY());
            final int savedState = canvas.save();
            canvas.scale(scaleX, scaleY);

            // Draw all the game's objects
            background.draw(canvas);

            // Prevent canvas from infinite scaling
            canvas.restoreToCount(savedState);
            */
        }
    }
}
