/*
 *******************************************************************************
 * Copyright (C) 1998-2004, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
 * Created on Dec 3, 2003
 *
 *******************************************************************************
 */
package com.ibm.icu.dev.tool.layout;

import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.lang.UProperty;

public class ArabicShaping {

    // arabic   shaping type code

    // shaping bit masks
    static final int MASK_SHAPE_RIGHT   = 1; // if this bit set, shapes to right
    static final int MASK_SHAPE_LEFT = 2;   // if this bit set, shapes to left
    static final int MASK_TRANSPARENT   = 4; // if this bit set, is transparent (ignore other bits)
    static final int MASK_NOSHAPE   = 8; // if this bit set, don't shape this char, i.e. tatweel

    // shaping values
    public static final int VALUE_NONE = 0;
    public static final int VALUE_RIGHT = MASK_SHAPE_RIGHT;
    public static final int VALUE_LEFT = MASK_SHAPE_LEFT;
    public static final int VALUE_DUAL = MASK_SHAPE_RIGHT | MASK_SHAPE_LEFT;
    public static final int VALUE_TRANSPARENT = MASK_TRANSPARENT;
    public static final int VALUE_NOSHAPE_DUAL = MASK_NOSHAPE | VALUE_DUAL;
    public static final int VALUE_NOSHAPE_NONE = MASK_NOSHAPE;

    public static int getShapeType(char ch)
    {
        int tt = UCharacter.getIntPropertyValue(ch, UProperty.JOINING_TYPE);
        
        switch(tt) {
            case UCharacter.JoiningType.JOIN_CAUSING:
                return VALUE_NOSHAPE_DUAL;
                
            case UCharacter.JoiningType.LEFT_JOINING:
                return VALUE_LEFT;
            
            case UCharacter.JoiningType.RIGHT_JOINING:
                return VALUE_RIGHT;
            
            case UCharacter.JoiningType.DUAL_JOINING:
                return VALUE_DUAL;
            
            case UCharacter.JoiningType.TRANSPARENT:
                return VALUE_TRANSPARENT;
                
            case UCharacter.JoiningType.NON_JOINING:
            default:
                return VALUE_NOSHAPE_NONE;                
        }
    }

    /*
     * Chars in logical order.
     * leftType is shaping code of char to logical left of range
     * rightType is shaping code of char to logical right of range
     */

    public static void shape(char[] chars, int leftType, int rightType, ClassTable isolClassTable) {
        // iterate in logical order from left to right
        //
        // the effective right char is the most recently encountered
        // non-transparent char
        //
        // four boolean states:
        //   the effective right char shapes
        //   the effective right char causes right shaping
        //   the current char shapes
        //   the current char causes left shaping
        //
        // if both cause shaping, then
        //   right += 2 (isolate to initial, or final to medial)
        //   cur += 1 (isolate to final)

        // ern is effective right logical index
        int ern = -1;

        boolean rightShapes = false;
        boolean rightCauses = (rightType & MASK_SHAPE_LEFT) != 0;

        for (int n = 0; n < chars.length; n++) {
            char c = chars[n];
            int t = getShapeType(c);

            if ((t & MASK_TRANSPARENT) != 0) {
                continue;
            }

            boolean curShapes = (t & MASK_NOSHAPE) == 0;
            boolean curCauses = (t & MASK_SHAPE_RIGHT) != 0;

            if (rightCauses && curCauses) {
                if (rightShapes) {
                    chars[ern] += 2;
                }

                if (curShapes) {
                    chars[n] = (char) (isolClassTable.getGlyphClassID(c) + 1);
                }
            } else {
                if (curShapes) {
                    chars[n] = (char) isolClassTable.getGlyphClassID(c);
                }
            }

            rightShapes = curShapes;
            rightCauses = (t & MASK_SHAPE_LEFT) != 0;
            ern = n;
        }

        if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) {
            chars[ern] += 2;
        }
    }
}
