/*
 * Copyright (C) 2007 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 jackpal.androidterm.emulatorview;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;

abstract class BaseTextRenderer implements TextRenderer {
    protected boolean mReverseVideo;

    protected int[] mPalette;

    protected static final int[] sXterm256Paint = {
            // 16 original colors
            // First 8 are dim
            0xff000000,  // black
            0xffcd0000,  // dim red
            0xff00cd00,  // dim green
            0xffcdcd00,  // dim yellow
            0xff0000ee,  // dim blue
            0xffcd00cd,  // dim magenta
            0xff00cdcd,  // dim cyan
            0xffe5e5e5,  // dim white
            // second 8 are bright
            0xff7f7f7f,  // medium grey
            0xffff0000,  // bright red
            0xff00ff00,  // bright green
            0xffffff00,  // bright yellow
            0xff5c5cff,  // light blue
            0xffff00ff,  // bright magenta
            0xff00ffff,  // bright cyan
            0xffffffff,  // bright white

            // 216 color cube, six shades of each color
            0xff000000,
            0xff00005f,
            0xff000087,
            0xff0000af,
            0xff0000d7,
            0xff0000ff,
            0xff005f00,
            0xff005f5f,
            0xff005f87,
            0xff005faf,
            0xff005fd7,
            0xff005fff,
            0xff008700,
            0xff00875f,
            0xff008787,
            0xff0087af,
            0xff0087d7,
            0xff0087ff,
            0xff00af00,
            0xff00af5f,
            0xff00af87,
            0xff00afaf,
            0xff00afd7,
            0xff00afff,
            0xff00d700,
            0xff00d75f,
            0xff00d787,
            0xff00d7af,
            0xff00d7d7,
            0xff00d7ff,
            0xff00ff00,
            0xff00ff5f,
            0xff00ff87,
            0xff00ffaf,
            0xff00ffd7,
            0xff00ffff,
            0xff5f0000,
            0xff5f005f,
            0xff5f0087,
            0xff5f00af,
            0xff5f00d7,
            0xff5f00ff,
            0xff5f5f00,
            0xff5f5f5f,
            0xff5f5f87,
            0xff5f5faf,
            0xff5f5fd7,
            0xff5f5fff,
            0xff5f8700,
            0xff5f875f,
            0xff5f8787,
            0xff5f87af,
            0xff5f87d7,
            0xff5f87ff,
            0xff5faf00,
            0xff5faf5f,
            0xff5faf87,
            0xff5fafaf,
            0xff5fafd7,
            0xff5fafff,
            0xff5fd700,
            0xff5fd75f,
            0xff5fd787,
            0xff5fd7af,
            0xff5fd7d7,
            0xff5fd7ff,
            0xff5fff00,
            0xff5fff5f,
            0xff5fff87,
            0xff5fffaf,
            0xff5fffd7,
            0xff5fffff,
            0xff870000,
            0xff87005f,
            0xff870087,
            0xff8700af,
            0xff8700d7,
            0xff8700ff,
            0xff875f00,
            0xff875f5f,
            0xff875f87,
            0xff875faf,
            0xff875fd7,
            0xff875fff,
            0xff878700,
            0xff87875f,
            0xff878787,
            0xff8787af,
            0xff8787d7,
            0xff8787ff,
            0xff87af00,
            0xff87af5f,
            0xff87af87,
            0xff87afaf,
            0xff87afd7,
            0xff87afff,
            0xff87d700,
            0xff87d75f,
            0xff87d787,
            0xff87d7af,
            0xff87d7d7,
            0xff87d7ff,
            0xff87ff00,
            0xff87ff5f,
            0xff87ff87,
            0xff87ffaf,
            0xff87ffd7,
            0xff87ffff,
            0xffaf0000,
            0xffaf005f,
            0xffaf0087,
            0xffaf00af,
            0xffaf00d7,
            0xffaf00ff,
            0xffaf5f00,
            0xffaf5f5f,
            0xffaf5f87,
            0xffaf5faf,
            0xffaf5fd7,
            0xffaf5fff,
            0xffaf8700,
            0xffaf875f,
            0xffaf8787,
            0xffaf87af,
            0xffaf87d7,
            0xffaf87ff,
            0xffafaf00,
            0xffafaf5f,
            0xffafaf87,
            0xffafafaf,
            0xffafafd7,
            0xffafafff,
            0xffafd700,
            0xffafd75f,
            0xffafd787,
            0xffafd7af,
            0xffafd7d7,
            0xffafd7ff,
            0xffafff00,
            0xffafff5f,
            0xffafff87,
            0xffafffaf,
            0xffafffd7,
            0xffafffff,
            0xffd70000,
            0xffd7005f,
            0xffd70087,
            0xffd700af,
            0xffd700d7,
            0xffd700ff,
            0xffd75f00,
            0xffd75f5f,
            0xffd75f87,
            0xffd75faf,
            0xffd75fd7,
            0xffd75fff,
            0xffd78700,
            0xffd7875f,
            0xffd78787,
            0xffd787af,
            0xffd787d7,
            0xffd787ff,
            0xffd7af00,
            0xffd7af5f,
            0xffd7af87,
            0xffd7afaf,
            0xffd7afd7,
            0xffd7afff,
            0xffd7d700,
            0xffd7d75f,
            0xffd7d787,
            0xffd7d7af,
            0xffd7d7d7,
            0xffd7d7ff,
            0xffd7ff00,
            0xffd7ff5f,
            0xffd7ff87,
            0xffd7ffaf,
            0xffd7ffd7,
            0xffd7ffff,
            0xffff0000,
            0xffff005f,
            0xffff0087,
            0xffff00af,
            0xffff00d7,
            0xffff00ff,
            0xffff5f00,
            0xffff5f5f,
            0xffff5f87,
            0xffff5faf,
            0xffff5fd7,
            0xffff5fff,
            0xffff8700,
            0xffff875f,
            0xffff8787,
            0xffff87af,
            0xffff87d7,
            0xffff87ff,
            0xffffaf00,
            0xffffaf5f,
            0xffffaf87,
            0xffffafaf,
            0xffffafd7,
            0xffffafff,
            0xffffd700,
            0xffffd75f,
            0xffffd787,
            0xffffd7af,
            0xffffd7d7,
            0xffffd7ff,
            0xffffff00,
            0xffffff5f,
            0xffffff87,
            0xffffffaf,
            0xffffffd7,
            0xffffffff,

            // 24 grey scale ramp
            0xff080808,
            0xff121212,
            0xff1c1c1c,
            0xff262626,
            0xff303030,
            0xff3a3a3a,
            0xff444444,
            0xff4e4e4e,
            0xff585858,
            0xff626262,
            0xff6c6c6c,
            0xff767676,
            0xff808080,
            0xff8a8a8a,
            0xff949494,
            0xff9e9e9e,
            0xffa8a8a8,
            0xffb2b2b2,
            0xffbcbcbc,
            0xffc6c6c6,
            0xffd0d0d0,
            0xffdadada,
            0xffe4e4e4,
            0xffeeeeee
    };

    static final ColorScheme defaultColorScheme =
            new ColorScheme(0xffcccccc, 0xff000000);

    private final Paint mCursorScreenPaint;
    private final Paint mCopyRedToAlphaPaint;
    private final Paint mCursorPaint;
    private final Paint mCursorStrokePaint;
    private final Path mShiftCursor;
    private final Path mAltCursor;
    private final Path mCtrlCursor;
    private final Path mFnCursor;
    private final Path mCursorFrame;
    private final RectF mTempSrc;
    private final RectF mTempDst;
    private final Matrix mScaleMatrix;
    private float mLastCharWidth;
    private float mLastCharHeight;
    private static final Matrix.ScaleToFit mScaleType = Matrix.ScaleToFit.FILL;

    private Bitmap mCursorBitmap;
    private Bitmap mWorkBitmap;
    private int mCursorBitmapCursorMode = -1;

    public BaseTextRenderer(ColorScheme scheme) {
        if (scheme == null) {
            scheme = defaultColorScheme;
        }
        setDefaultColors(scheme);

        mCursorScreenPaint = new Paint();
        mCursorScreenPaint.setColor(scheme.getCursorBackColor());

        // Cursor paint and cursor stroke paint are used to draw a grayscale mask that's converted
        // to an alpha8 texture. Only the red channel's value matters.
        mCursorPaint = new Paint();
        mCursorPaint.setColor(0xffffffff);
        mCursorPaint.setAntiAlias(true);

        mCursorStrokePaint = new Paint(mCursorPaint);
        mCursorStrokePaint.setStrokeWidth(0.1f);
        mCursorStrokePaint.setStyle(Paint.Style.STROKE);

        mCopyRedToAlphaPaint = new Paint();
        ColorMatrix cm = new ColorMatrix();
        cm.set(new float[]{
                0, 0, 0, 0, 0,
                0, 0, 0, 0, 0,
                0, 0, 0, 0, 0,
                1, 0, 0, 0, 0});
        mCopyRedToAlphaPaint.setColorFilter(new ColorMatrixColorFilter(cm));

        mShiftCursor = new Path();
        mShiftCursor.lineTo(0.5f, 0.33f);
        mShiftCursor.lineTo(1.0f, 0.0f);

        mAltCursor = new Path();
        mAltCursor.moveTo(0.0f, 1.0f);
        mAltCursor.lineTo(0.5f, 0.66f);
        mAltCursor.lineTo(1.0f, 1.0f);

        mCtrlCursor = new Path();
        mCtrlCursor.moveTo(0.0f, 0.00f);
        mCtrlCursor.lineTo(1.0f, 0.5f);
        mCtrlCursor.lineTo(0.0f, 1.00f);

        mCursorFrame = new Path();
        mCursorFrame.moveTo(0.0f, 0.00f);
        mCursorFrame.lineTo(0.0f, 1.0f);
        mCursorFrame.lineTo(1.0f, 1.00f);
        mCursorFrame.lineTo(1.0f, 0.00f);
        mCursorFrame.lineTo(0.0f, 0.00f);

        mFnCursor = new Path();
        mFnCursor.moveTo(1.0f, 0.00f);
        mFnCursor.lineTo(0.0f, 0.5f);
        mFnCursor.lineTo(1.0f, 1.00f);

        // For creating the transform when the terminal resizes
        mTempSrc = new RectF();
        mTempSrc.set(0.0f, 0.0f, 1.0f, 1.0f);
        mTempDst = new RectF();
        mScaleMatrix = new Matrix();
    }

    public void setReverseVideo(boolean reverseVideo) {
        mReverseVideo = reverseVideo;
    }

    static float mCursorHeight = 1.0f;
    static int mCursorHeightMode = 0;
    static int mCursorHeightModeDefault = mCursorHeightMode;

    static public void setCursorHeightModeDefault(int cursorHeight) {
        mCursorHeightModeDefault = cursorHeight;
        setCursorHeightMode(cursorHeight);
    }

    static public void setCursorHeightMode(int cursorHeight) {
        mCursorHeightMode = cursorHeight;
        mCursorHeight = (mCursorHeightMode == 1 || mCursorHeightMode == 3) ? 3.0f : 1.0f;
    }

    static public int getCursorHeightMode() {
        return mCursorHeightModeDefault;
    }

    private void setDefaultColors(ColorScheme scheme) {
        mPalette = cloneDefaultColors();
        mPalette[TextStyle.ciForeground] = scheme.getForeColor();
        mPalette[TextStyle.ciBackground] = scheme.getBackColor();
        mPalette[TextStyle.ciCursorForeground] = scheme.getCursorForeColor();
        mPalette[TextStyle.ciCursorBackground] = scheme.getCursorBackColor();
    }

    private static int[] cloneDefaultColors() {
        int length = sXterm256Paint.length;
        int[] clone = new int[TextStyle.ciColorLength];
        System.arraycopy(sXterm256Paint, 0, clone, 0, length);
        return clone;
    }

    protected void drawCursorImp(Canvas canvas, float x, float y, float charWidth, float charHeight, int cursorMode) {
        if (cursorMode == 0) {
            float cursorWidth = charWidth;
            if (mCursorHeightMode >= 4) charWidth = charWidth / 5.0f;
            canvas.drawRect(x, y - charHeight / mCursorHeight, x + charWidth, y, mCursorScreenPaint);
            return;
        }

        // Fancy cursor. Draw an offscreen cursor shape, then blit it on screen.

        // Has the character size changed?

        if (charWidth != mLastCharWidth || charHeight != mLastCharHeight) {
            mLastCharWidth = charWidth;
            mLastCharHeight = charHeight;
            mTempDst.set(0.0f, 0.0f, charWidth, charHeight);
            mScaleMatrix.setRectToRect(mTempSrc, mTempDst, mScaleType);
            mCursorBitmap = Bitmap.createBitmap((int) charWidth, (int) charHeight,
                    Bitmap.Config.ALPHA_8);
            mWorkBitmap = Bitmap.createBitmap((int) charWidth, (int) charHeight,
                    Bitmap.Config.ARGB_8888);
            mCursorBitmapCursorMode = -1;
        }

        // Has the cursor mode changed ?

        if (cursorMode != mCursorBitmapCursorMode) {
            mCursorBitmapCursorMode = cursorMode;
            mWorkBitmap.eraseColor(0xff000000);
            Canvas workCanvas = new Canvas(mWorkBitmap);
            workCanvas.concat(mScaleMatrix);
            drawCursorHelper(workCanvas, mShiftCursor, cursorMode, MODE_SHIFT_SHIFT);
            drawCursorHelper(workCanvas, mAltCursor, cursorMode, MODE_ALT_SHIFT);
            drawCursorHelper(workCanvas, mCtrlCursor, cursorMode, MODE_CTRL_SHIFT);
            drawCursorHelper(workCanvas, mFnCursor, cursorMode, MODE_FN_SHIFT);
            drawCursorHelper(workCanvas, mCursorFrame, MODE_ON, 0);

            mCursorBitmap.eraseColor(0);
            Canvas bitmapCanvas = new Canvas(mCursorBitmap);
            bitmapCanvas.drawBitmap(mWorkBitmap, 0, 0, mCopyRedToAlphaPaint);
        }

        canvas.drawBitmap(mCursorBitmap, x, y - charHeight, mCursorScreenPaint);
    }

    private void drawCursorHelper(Canvas canvas, Path path, int mode, int shift) {
        switch ((mode >> shift) & MODE_MASK) {
            case MODE_ON:
                canvas.drawPath(path, mCursorStrokePaint);
                break;
            case MODE_LOCKED:
                canvas.drawPath(path, mCursorPaint);
                break;
        }
    }
}

