/*
 * Copyright (C) 2010 Google Inc.
 *
 * 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.inputmethod.keyboard;

import com.android.inputmethod.latin.R;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Rect;

import java.util.List;

public class MiniKeyboardBuilder {
    private final Resources mRes;
    private final MiniKeyboard mKeyboard;
    private final CharSequence[] mPopupCharacters;
    private final MiniKeyboardLayoutParams mParams;

    /* package */ static class MiniKeyboardLayoutParams {
        public final int mKeyWidth;
        public final int mRowHeight;
        /* package */ final boolean mTopRowNeedsCentering;
        public final int mNumRows;
        public final int mNumColumns;
        public final int mLeftKeys;
        public final int mRightKeys; // includes default key.

        /**
         * The object holding mini keyboard layout parameters.
         *
         * @param numKeys number of keys in this mini keyboard.
         * @param maxColumns number of maximum columns of this mini keyboard.
         * @param keyWidth mini keyboard key width in pixel, including horizontal gap.
         * @param rowHeight mini keyboard row height in pixel, including vertical gap.
         * @param coordXInParent coordinate x of the popup key in parent keyboard.
         * @param parentKeyboardWidth parent keyboard width in pixel.
         */
        public MiniKeyboardLayoutParams(int numKeys, int maxColumns, int keyWidth, int rowHeight,
                int coordXInParent, int parentKeyboardWidth) {
            if (parentKeyboardWidth / keyWidth < maxColumns)
                throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
                        + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
            final int numRows = (numKeys + maxColumns - 1) / maxColumns;
            mKeyWidth = keyWidth;
            mRowHeight = rowHeight;
            mNumRows = numRows;

            final int numColumns = Math.min(numKeys, maxColumns);
            final int topRowKeys = numKeys % numColumns;
            mNumColumns = numColumns;
            mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0;

            final int numLeftKeys = (numColumns - 1) / 2;
            final int numRightKeys = numColumns - numLeftKeys; // including default key.
            final int maxLeftKeys = coordXInParent / keyWidth;
            final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
            if (numLeftKeys > maxLeftKeys) {
                mLeftKeys = maxLeftKeys;
                mRightKeys = numColumns - maxLeftKeys;
            } else if (numRightKeys > maxRightKeys) {
                mLeftKeys = numColumns - maxRightKeys;
                mRightKeys = maxRightKeys;
            } else {
                mLeftKeys = numLeftKeys;
                mRightKeys = numRightKeys;
            }
        }

        // Return key position according to column count (0 is default).
        /* package */ int getColumnPos(int n) {
            final int col = n % mNumColumns;
            if (col == 0) {
                // default position.
                return 0;
            }
            int pos = 0;
            int right = 1; // include default position key.
            int left = 0;
            int i = 0;
            while (true) {
                // Assign right key if available.
                if (right < mRightKeys) {
                    pos = right;
                    right++;
                    i++;
                }
                if (i >= col)
                    break;
                // Assign left key if available.
                if (left < mLeftKeys) {
                    left++;
                    pos = -left;
                    i++;
                }
                if (i >= col)
                    break;
            }
            return pos;
        }

        public int getDefaultKeyCoordX() {
            return mLeftKeys * mKeyWidth;
        }

        public int getX(int n, int row) {
            final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
            if (isLastRow(row) && mTopRowNeedsCentering)
                return x - mKeyWidth / 2;
            return x;
        }

        public int getY(int row) {
            return (mNumRows - 1 - row) * mRowHeight;
        }

        public int getRowFlags(int row) {
            int rowFlags = 0;
            if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
            if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
            return rowFlags;
        }

        private boolean isLastRow(int rowCount) {
            return rowCount == mNumRows - 1;
        }
    }

    public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) {
        final Context context = view.getContext();
        mRes = context.getResources();
        final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
        mKeyboard = keyboard;
        mPopupCharacters = popupKey.mPopupCharacters;

        final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
        final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
                mPopupCharacters.length, popupKey.mMaxPopupColumn,
                keyWidth, keyboard.getRowHeight(),
                popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2,
                view.getMeasuredWidth());
        mParams = params;

        keyboard.setHeight(params.mNumRows * params.mRowHeight - keyboard.getVerticalGap());
        keyboard.setMinWidth(params.mNumColumns * params.mKeyWidth);
        keyboard.setDefaultCoordX(params.getDefaultKeyCoordX() + params.mKeyWidth / 2);
    }

    private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters,
            int minKeyWidth) {
        Paint paint = null;
        Rect bounds = null;
        int maxWidth = 0;
        for (CharSequence popupSpec : popupCharacters) {
            final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
            // If the label is single letter, minKeyWidth is enough to hold the label.
            if (label != null && label.length() > 1) {
                if (paint == null) {
                    paint = new Paint();
                    paint.setAntiAlias(true);
                }
                final int labelSize = view.getLabelSizeAndSetPaint(label, 0, paint);
                paint.setTextSize(labelSize);
                if (bounds == null) bounds = new Rect();
                paint.getTextBounds(label.toString(), 0, label.length(), bounds);
                if (maxWidth < bounds.width())
                    maxWidth = bounds.width();
            }
        }
        final int horizontalPadding = (int)view.getContext().getResources().getDimension(
                R.dimen.mini_keyboard_key_horizontal_padding);
        return Math.max(minKeyWidth, maxWidth + horizontalPadding);
    }

    public MiniKeyboard build() {
        final MiniKeyboard keyboard = mKeyboard;
        final List<Key> keys = keyboard.getKeys();
        final MiniKeyboardLayoutParams params = mParams;
        for (int n = 0; n < mPopupCharacters.length; n++) {
            final CharSequence label = mPopupCharacters[n];
            final int row = n / params.mNumColumns;
            final Key key = new Key(mRes, keyboard, label, params.getX(n, row), params.getY(row),
                    params.mKeyWidth, params.getRowFlags(row));
            keys.add(key);
        }
        return keyboard;
    }
}
