/*
    DroidFish - An Android chess program.
    Copyright (C) 2015  Peter Österlund, peterosterlund2@gmail.com

    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/>.
*/

package org.petero.droidfish.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;

/** Custom view for displaying move list.
 *  This is much faster than using a TextView. */
public class MoveListView extends View {
    private CharSequence text = null;
    private Layout layout = null;
    private int layoutWidth = -1;
    private TextPaint textPaint;
    private Typeface defaultTypeface;
    private float extraSpacing = 0.0f;

    /** Constructor. */
    public MoveListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.density = getResources().getDisplayMetrics().density;
        defaultTypeface = Typeface.create("monospace", Typeface.NORMAL);
        textPaint.setTypeface(defaultTypeface);
    }

    /** Set text to display. */
    public void setText(CharSequence text) {
        if (text != this.text) {
            this.text = text;
            createLayout(getWidth());
            requestLayout();
        }
        invalidate();
    }

    /** Set typeface and text size. If tf is null the default typeface is used. */
    public void setTypeface(Typeface tf, float size) {
        boolean modified = false;
        float spacing = tf == null ? 0.0f : 1.0f; // Figurine font looks better with extra spacing
        if (spacing != extraSpacing) {
            extraSpacing = spacing;
            modified = true;
        }
        if (tf == null)
            tf = defaultTypeface;
        if (tf != textPaint.getTypeface()) {
            textPaint.setTypeface(tf);
            modified = true;
        }
        DisplayMetrics metric = getContext().getResources().getDisplayMetrics();
        size *= metric.scaledDensity;
        if (size != textPaint.getTextSize()) {
            textPaint.setTextSize(size);
            modified = true;
        }
        if (modified) {
            createLayout(getWidth());
            requestLayout();
            invalidate();
        }
    }

    public void setTextColor(int color) {
        if (color != textPaint.getColor()) {
            textPaint.setColor(color);
            invalidate();
        }
    }

    /** Get line number corresponding to a character offset,
     *  or -1 if layout has not been created yet. */
    public int getLineForOffset(int currPos) {
        if (layout == null)
            return -1;
        return layout.getLineForOffset(currPos);
    }

    /** Get line height in pixels. */
    public int getLineHeight() {
        return textPaint.getFontMetricsInt(null);
    }

    /** Get the Y scroll value required to put line "lineNo" at the top of the view. */
    public int getLineStartY(int lineNo) {
        if (lineNo < 0)
            return 0;
        lineNo = Math.min(lineNo, layout.getLineCount());
        return layout.getLineTop(lineNo);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);
        int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);

        int width = getMeasuredWidth();
        switch (MeasureSpec.getMode(widthMeasureSpec)) {
        case MeasureSpec.UNSPECIFIED:
            break;
        case MeasureSpec.EXACTLY:
            width = widthMeasure;
            break;
        case MeasureSpec.AT_MOST:
            width = Math.min(width, widthMeasure);
            break;
        }

        if (width != layoutWidth)
            createLayout(width);

        int height = 0;
        if (layout != null) {
            int nLines = layout.getLineCount();
            height = nLines * getLineHeight();
            ViewParent p = getParent();
            if (p != null)
                p = p.getParent();
            if (p instanceof MyRelativeLayout)
                height = getLineStartY(nLines - 1) + ((MyRelativeLayout)p).getNewHeight();
        }
        switch (MeasureSpec.getMode(heightMeasureSpec)) {
        case MeasureSpec.UNSPECIFIED:
            break;
        case MeasureSpec.EXACTLY:
            height = heightMeasure;
            break;
        case MeasureSpec.AT_MOST:
            height = Math.min(height, heightMeasure);
            break;
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (layout != null) {
            canvas.save();
            canvas.translate(getPaddingLeft(), getPaddingTop());
            layout.draw(canvas);
            canvas.restore();
        }
    }

    public interface OnLinkClickListener {
        boolean onLinkClick(int offs);
    }
    private OnLinkClickListener onLinkClickListener;

    public void setOnLinkClickListener(OnLinkClickListener listener) {
        onLinkClickListener = listener;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getActionMasked();
        boolean ret = super.onTouchEvent(event);
        if ((action == MotionEvent.ACTION_UP) && (layout != null) &&
            (onLinkClickListener != null)) {
            int x = (int)event.getX() - getPaddingLeft() + getScrollX();
            int y = (int)event.getY() - getPaddingTop()  + getScrollY();
            int line = layout.getLineForVertical(y);
            int offs = layout.getOffsetForHorizontal(line, x);
            if (onLinkClickListener.onLinkClick(offs))
                return true;
        }
        return ret;
    }

    /** Create a StaticLayout corresponding to the current text. */
    private void createLayout(int width) {
        if (width <= 0)
            return;
        if (text == null) {
            layout = null;
            layoutWidth = -1;
        } else {
            layout = new StaticLayout(text, textPaint, width,
                                      Alignment.ALIGN_NORMAL, 1.0f, extraSpacing, true);
            layoutWidth = width;
        }
    }
}
