/*
 * Copyright (C) 2006 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 android.text;

import com.android.internal.util.ArrayUtils;

class PackedObjectVector<E>
{
    private int mColumns;
    private int mRows;

    private int mRowGapStart;
    private int mRowGapLength;

    private Object[] mValues;

    public
    PackedObjectVector(int columns)
    {
        mColumns = columns;
        mRows = ArrayUtils.idealIntArraySize(0) / mColumns;

        mRowGapStart = 0;
        mRowGapLength = mRows;

        mValues = new Object[mRows * mColumns];
    }

    public E
    getValue(int row, int column)
    {
        if (row >= mRowGapStart)
            row += mRowGapLength;

        Object value = mValues[row * mColumns + column];

        return (E) value;
    }

    public void
    setValue(int row, int column, E value)
    {
        if (row >= mRowGapStart)
            row += mRowGapLength;

        mValues[row * mColumns + column] = value;
    }

    public void
    insertAt(int row, E[] values)
    {
        moveRowGapTo(row);

        if (mRowGapLength == 0)
            growBuffer();

        mRowGapStart++;
        mRowGapLength--;

        if (values == null)
            for (int i = 0; i < mColumns; i++)
                setValue(row, i, null);
        else
            for (int i = 0; i < mColumns; i++)
                setValue(row, i, values[i]);
    }

    public void
    deleteAt(int row, int count)
    {
        moveRowGapTo(row + count);

        mRowGapStart -= count;
        mRowGapLength += count;

        if (mRowGapLength > size() * 2)
        {
            // dump();
            // growBuffer();
        }
    }

    public int
    size()
    {
        return mRows - mRowGapLength;
    }

    public int
    width()
    {
        return mColumns;
    }

    private void
    growBuffer()
    {
        int newsize = size() + 1;
        newsize = ArrayUtils.idealIntArraySize(newsize * mColumns) / mColumns;
        Object[] newvalues = new Object[newsize * mColumns];

        int after = mRows - (mRowGapStart + mRowGapLength);

        System.arraycopy(mValues, 0, newvalues, 0, mColumns * mRowGapStart);
        System.arraycopy(mValues, (mRows - after) * mColumns, newvalues, (newsize - after) * mColumns, after * mColumns);

        mRowGapLength += newsize - mRows;
        mRows = newsize;
        mValues = newvalues;
    }

    private void
    moveRowGapTo(int where)
    {
        if (where == mRowGapStart)
            return;

        if (where > mRowGapStart)
        {
            int moving = where + mRowGapLength - (mRowGapStart + mRowGapLength);

            for (int i = mRowGapStart + mRowGapLength; i < mRowGapStart + mRowGapLength + moving; i++)
            {
                int destrow = i - (mRowGapStart + mRowGapLength) + mRowGapStart;

                for (int j = 0; j < mColumns; j++)
                {
                    Object val = mValues[i * mColumns + j];

                    mValues[destrow * mColumns + j] = val;
                }
            }
        }
        else /* where < mRowGapStart */
        {
            int moving = mRowGapStart - where;

            for (int i = where + moving - 1; i >= where; i--)
            {
                int destrow = i - where + mRowGapStart + mRowGapLength - moving;

                for (int j = 0; j < mColumns; j++)
                {
                    Object val = mValues[i * mColumns + j];

                    mValues[destrow * mColumns + j] = val;
                }
            }
        }

        mRowGapStart = where;
    }

    public void // XXX
    dump()
    {
        for (int i = 0; i < mRows; i++)
        {
            for (int j = 0; j < mColumns; j++)
            {
                Object val = mValues[i * mColumns + j];

                if (i < mRowGapStart || i >= mRowGapStart + mRowGapLength)
                    System.out.print(val + " ");
                else
                    System.out.print("(" + val + ") ");
            }

            System.out.print(" << \n");
        }

        System.out.print("-----\n\n");
    }
}
