/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.egg.paint;

import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;

import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Magnifier;

import com.android.egg.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.IntStream;

public class PaintActivity extends Activity {
    private static final float MAX_BRUSH_WIDTH_DP = 100f;
    private static final float MIN_BRUSH_WIDTH_DP = 1f;

    private static final int NUM_BRUSHES = 6;
    private static final int NUM_COLORS = 6;

    private Painting painting = null;
    private CutoutAvoidingToolbar toolbar = null;
    private LinearLayout brushes = null;
    private LinearLayout colors = null;
    private Magnifier magnifier = null;
    private boolean sampling = false;

    private View.OnClickListener buttonHandler = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btnBrush:
                    view.setSelected(true);
                    hideToolbar(colors);
                    toggleToolbar(brushes);
                    break;
                case R.id.btnColor:
                    view.setSelected(true);
                    hideToolbar(brushes);
                    toggleToolbar(colors);
                    break;
                case R.id.btnClear:
                    painting.clear();
                    break;
                case R.id.btnSample:
                    sampling = true;
                    view.setSelected(true);
                    break;
                case R.id.btnZen:
                    painting.setZenMode(!painting.getZenMode());
                    view.animate()
                            .setStartDelay(200)
                            .setInterpolator(new OvershootInterpolator())
                            .rotation(painting.getZenMode() ? 0f : 90f);
                    break;
            }
        }
    };

    private void showToolbar(View bar) {
        if (bar.getVisibility() != View.GONE) return;
        bar.setVisibility(View.VISIBLE);
        bar.setTranslationY(toolbar.getHeight()/2);
        bar.animate()
                .translationY(toolbar.getHeight())
                .alpha(1f)
                .setDuration(220)
                .start();
    }

    private void hideToolbar(View bar) {
        if (bar.getVisibility() != View.VISIBLE) return;
        bar.animate()
                .translationY(toolbar.getHeight()/2)
                .alpha(0f)
                .setDuration(150)
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {
                        bar.setVisibility(View.GONE);
                    }
                })
                .start();
    }

    private void toggleToolbar(View bar) {
        if (bar.getVisibility() == View.VISIBLE) {
            hideToolbar(bar);
        } else {
            showToolbar(bar);
        }
    }

    private BrushPropertyDrawable widthButtonDrawable;
    private BrushPropertyDrawable colorButtonDrawable;
    private float maxBrushWidth, minBrushWidth;
    private int nightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;

    static final float lerp(float f, float a, float b) {
        return a + (b-a) * f;
    }

    void setupViews(Painting oldPainting) {
        setContentView(R.layout.activity_paint);

        painting = oldPainting != null ? oldPainting : new Painting(this);
        ((FrameLayout) findViewById(R.id.contentView)).addView(painting,
                new FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));

        painting.setPaperColor(getColor(R.color.paper_color));
        painting.setPaintColor(getColor(R.color.paint_color));

        toolbar = findViewById(R.id.toolbar);
        brushes = findViewById(R.id.brushes);
        colors = findViewById(R.id.colors);

        magnifier = new Magnifier(painting);

        painting.setOnTouchListener(
                new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View view, MotionEvent event) {
                        switch (event.getActionMasked()) {
                            case ACTION_DOWN:
                            case ACTION_MOVE:
                                if (sampling) {
                                    magnifier.show(event.getX(), event.getY());
                                    colorButtonDrawable.setWellColor(
                                            painting.sampleAt(event.getX(), event.getY()));
                                    return true;
                                }
                                break;
                            case ACTION_CANCEL:
                                if (sampling) {
                                    findViewById(R.id.btnSample).setSelected(false);
                                    sampling = false;
                                    magnifier.dismiss();
                                }
                                break;
                            case ACTION_UP:
                                if (sampling) {
                                    findViewById(R.id.btnSample).setSelected(false);
                                    sampling = false;
                                    magnifier.dismiss();
                                    painting.setPaintColor(
                                            painting.sampleAt(event.getX(), event.getY()));
                                    refreshBrushAndColor();
                                }
                                break;
                        }
                        return false; // allow view to continue handling
                    }
                });

        findViewById(R.id.btnBrush).setOnClickListener(buttonHandler);
        findViewById(R.id.btnColor).setOnClickListener(buttonHandler);
        findViewById(R.id.btnClear).setOnClickListener(buttonHandler);
        findViewById(R.id.btnSample).setOnClickListener(buttonHandler);
        findViewById(R.id.btnZen).setOnClickListener(buttonHandler);

        findViewById(R.id.btnColor).setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                colors.removeAllViews();
                showToolbar(colors);
                refreshBrushAndColor();
                return true;
            }
        });

        findViewById(R.id.btnClear).setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                painting.invertContents();
                return true;
            }
        });

        widthButtonDrawable = new BrushPropertyDrawable(this);
        widthButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));
        colorButtonDrawable = new BrushPropertyDrawable(this);
        colorButtonDrawable.setFrameColor(getColor(R.color.toolbar_icon_color));

        ((ImageButton) findViewById(R.id.btnBrush)).setImageDrawable(widthButtonDrawable);
        ((ImageButton) findViewById(R.id.btnColor)).setImageDrawable(colorButtonDrawable);

        refreshBrushAndColor();
    }

    private void refreshBrushAndColor() {
        final LinearLayout.LayoutParams button_lp = new LinearLayout.LayoutParams(
                0, ViewGroup.LayoutParams.WRAP_CONTENT);
        button_lp.weight = 1f;
        if (brushes.getChildCount() == 0) {
            for (int i = 0; i < NUM_BRUSHES; i++) {
                final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
                icon.setFrameColor(getColor(R.color.toolbar_icon_color));
                // exponentially increasing brush size
                final float width = lerp(
                        (float) Math.pow((float) i / NUM_BRUSHES, 2f), minBrushWidth,
                        maxBrushWidth);
                icon.setWellScale(width / maxBrushWidth);
                icon.setWellColor(getColor(R.color.toolbar_icon_color));
                final ImageButton button = new ImageButton(this);
                button.setImageDrawable(icon);
                button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
                button.setOnClickListener(
                        new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                brushes.setSelected(false);
                                hideToolbar(brushes);
                                painting.setBrushWidth(width);
                                refreshBrushAndColor();
                            }
                        });
                brushes.addView(button, button_lp);
            }
        }

        if (colors.getChildCount() == 0) {
            final Palette pal = new Palette(NUM_COLORS);
            for (final int c : IntStream.concat(
                    IntStream.of(Color.BLACK, Color.WHITE),
                    Arrays.stream(pal.getColors())
            ).toArray()) {
                final BrushPropertyDrawable icon = new BrushPropertyDrawable(this);
                icon.setFrameColor(getColor(R.color.toolbar_icon_color));
                icon.setWellColor(c);
                final ImageButton button = new ImageButton(this);
                button.setImageDrawable(icon);
                button.setBackground(getDrawable(R.drawable.toolbar_button_bg));
                button.setOnClickListener(
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            colors.setSelected(false);
                            hideToolbar(colors);
                            painting.setPaintColor(c);
                            refreshBrushAndColor();
                        }
                    });
                colors.addView(button, button_lp);
            }
        }

        widthButtonDrawable.setWellScale(painting.getBrushWidth() / maxBrushWidth);
        widthButtonDrawable.setWellColor(painting.getPaintColor());
        colorButtonDrawable.setWellColor(painting.getPaintColor());
    }

    private void refreshNightMode(Configuration config) {
        int newNightMode =
                (config.uiMode & Configuration.UI_MODE_NIGHT_MASK);
        if (nightMode != newNightMode) {
            if (nightMode != Configuration.UI_MODE_NIGHT_UNDEFINED) {
                painting.invertContents();

                ((ViewGroup) painting.getParent()).removeView(painting);
                setupViews(painting);

                final View decorView = getWindow().getDecorView();
                int decorSUIV = decorView.getSystemUiVisibility();

                if (newNightMode == Configuration.UI_MODE_NIGHT_YES) {
                    decorView.setSystemUiVisibility(
                            decorSUIV & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
                } else {
                    decorView.setSystemUiVisibility(
                            decorSUIV | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
                }
            }
            nightMode = newNightMode;
        }
    }

    public PaintActivity() {

    }

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);

        painting.onTrimMemory();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        refreshNightMode(newConfig);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        WindowManager.LayoutParams lp = getWindow().getAttributes();
        lp.flags = lp.flags
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        getWindow().setAttributes(lp);

        maxBrushWidth = MAX_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;
        minBrushWidth = MIN_BRUSH_WIDTH_DP * getResources().getDisplayMetrics().density;

        setupViews(null);
        refreshNightMode(getResources().getConfiguration());
    }

    @Override
    public void onPostResume() {
        super.onPostResume();
    }

}