/*
 * $Id: TextStyles.java,v 1.5 2004/06/27 17:08:23 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: TextStyles.java,v $
 * Revision 1.5  2004/06/27 17:08:23  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.4  2003/12/24 10:12:05  bigmac
 * Projektweite Import-Optimierung
 *
 * Revision 1.3  2003/04/23 14:55:34  lawern
 * Ergänzungen für Volltextverarbeitung
 *
 * Revision 1.2  2003/03/20 09:11:35  lawern
 * Konverter und Analyse überarbeitet
 *
 * Revision 1.1  2003/03/07 11:56:57  lawern
 * initiale Version
 *
 */
package vkc.analyse;

import java.util.ArrayList;

import vkc.util.TextMiningUtils;


/**
 * Diese Klasse dient zum Zwischenspeichern und Analysieren von Ergebnisse aus
 * den Rendering- und  Analysevorgängen.
 *
 * @author lawern
 */
public final class TextStyles extends ArrayList {
    private static final boolean debug = false;

    /** Präzision mit der die Gewichte berechnet werden */
    public static final int WEIGHT_PRECISION = 5;

    //private ArrayList styles = new ArrayList();
    //Statistik
    private boolean statisticCalculated = false;

    // fontSize  | 01 | .. | 09 | 10 | .. | 64
    // ----------+----+----+----+----+----+----
    // normal    |    |    |    |    |    |     (+0)
    // ----------+----+----+----+----+----+----
    // bold      |    |    |    |    |    |     (+64)
    // ----------+----+----+----+----+----+----
    // italic    |    |    |    |    |    |     (+128)
    // ----------+----+----+----+----+----+----
    // b,i       |    |    |    |    |    |     (+192)
    // ----------+----+----+----+----+----+----
    // underlined|    |    |    |    |    |     (+256)
    // ----------+----+----+----+----+----+----
    // ...                                       ...
    // ----------+----+----+----+----+----+----
    // b,i,u     |    |    |    |    |    |     (+448)
    // ----------+----+----+----+----+----+----
    // Summe     |    |    |    |    |    |     (+512)
    //    
    private int[] styleMatrix = new int[577];

    /**
     * Container für die in einem Textdokument verwendeten Text-Styles.
     */
    public TextStyles() {
        //Initialisiert und Setzt die internen Statistiken zurück.
        for (int i = 0; i < 577; i++)
            styleMatrix[i] = 0;
    }

    /**
     * Fügt einen neuen TextStyle ein.
     */
    public void add(TextStyle style) {
        super.add(style);

        int count = style.length();

        //erhoehe in der StyleMatrix diesen Style um die Anzahl seiner Woerter.
        styleMatrix[style.style] += count;

        //Summe für Schrifgröße erhöhen
        styleMatrix[512 | style.fontSize] += count;
    }

    /**
     * Berechnung des Relevanz-Offset für die verschiedenen
     * Auszeichnungsmerkmale einer Schriftgröße
     *
     * @param fontSize Schriftgröße für welche die Offsets berechnet werden
     *        sollen
     * @param sizeStep maximaler Wert um den der Offset variieren darf
     */
    private void calculateStyleOffsets(int fontSize, int baseWeight) {
        int tmpValue;
        int maxValue = 0;
        int maxStyle = 0;
        int minValue = 0;

        //Feststellung der am Haufigsten verwendeten Auszeichnungskombinationen
        for (int i = 0; i < 449; i += 64) {
            tmpValue = styleMatrix[i | fontSize];

            if (tmpValue > maxValue) {
                maxValue = tmpValue;
                maxStyle = i;

                if (minValue == 0) {
                    minValue = tmpValue;
                }
            } else {
                if (tmpValue < minValue) {
                    minValue = tmpValue;
                }
            }
        }

        //Basisgewicht für die am häufigsten benutzte Auszeichnungskombination setzen
        styleMatrix[maxStyle | fontSize] = baseWeight;

        if (debug) {
            System.out.println("fontSize:" + fontSize + " style:" + maxStyle +
                " value:" + baseWeight + " Times used:" + maxValue);
        }

        //Gab es ansonsten noch weitere Auszeichnungskombinationen?
        if (minValue != maxValue) {
            //Berechnung der Relevanz-Offsets
            int baseOffset = baseWeight + 50;

            for (int i = 0; i < 449; i += 64) {
                tmpValue = styleMatrix[i | fontSize];

                if (tmpValue != 0) {
                    if (i != maxStyle) {
                        styleMatrix[i | fontSize] = baseOffset -
                            ((tmpValue * 50) / maxValue);

                        if (debug) {
                            System.out.println("fontSize:" + fontSize +
                                " style:" + i + " value:" +
                                styleMatrix[i | fontSize] + " Times used:" +
                                tmpValue);
                        }
                    }
                }
            }
        }
    }

    /**
     * Berechnet die statistischen Daten die für die Methode getWeight()
     * benötigt werden.
     */
    private void calculateStatistic() {
        int currentFontSize;

        //häufigsten Font ermitteln. Ergebnis steht in maxFont. Rang des Fonts ermitteln.
        // 	int maxFontSize = 0;
        // 	int maxFontRank = 0;
        int rankCounter = 0;

        // 	maxFont = 0;
        // 	for (int i=1; i<65; i++){
        // 	    currentFontSize = styleMatrix[512|i];
        // 	    if (currentFontSize > maxFontSize){
        // 		maxFontSize = currentFontSize;
        // 		maxFont = i;
        // 		rankCounter++;
        // 		maxFontRank = rankCounter;
        // 	    } else {
        // 		if (currentFontSize > 0)
        // 		    rankCounter++;
        // 	    }
        // 	}
        //System.out.println("maxFont:"+maxFont);
        //erste verwendete Schriftgröße finden
        int lastUsedFontSize = 0;

        for (int i = 1; i < 65; i++) {
            currentFontSize = styleMatrix[512 | i];

            if (currentFontSize > 0) {
                lastUsedFontSize = i;

                break;
            }
        }

        //Berechnung des Relevanz-Offset für die verschiedenen Auszeichnungsmerkmale einer
        //Schriftgröße.
        rankCounter = 0;

        for (int i = lastUsedFontSize + 1; i < 65; i++) {
            currentFontSize = styleMatrix[512 | i];

            if (currentFontSize > 0) {
                rankCounter++;

                //Basisgewicht berechnen
                //int baseWeight = ((rankCounter - maxFontRank) + 1) * 100;
                int baseWeight = rankCounter * 100;

                //Style-Offsets für die vorhergehende Font-Größe berechnen
                calculateStyleOffsets(lastUsedFontSize, baseWeight);

                lastUsedFontSize = i;
            }
        }

        //Basisgewicht des größten Font berechnen
        int baseWeight = (rankCounter + 1) * 100;

        //Style-Offsets für den größten Font berechnen
        calculateStyleOffsets(lastUsedFontSize, baseWeight);

        //überflüssige Werte löschen
        for (int i = 513; i < 577; i++)
            styleMatrix[i] = 0;

        //Gewichte minimieren
        float ggt = TextMiningUtils.ggT(styleMatrix, WEIGHT_PRECISION);

        if (ggt > 1) {
            for (int i = styleMatrix.length - 1; i > 0; i--) {
                if (styleMatrix[i] != 0) {
                    styleMatrix[i] = Math.round(styleMatrix[i] / ggt);
                }
            }
        }
    }

    /**
     * Gibt den angeforderten TextStyle zurück und setzt gleichzeitig das
     * Gewicht.
     */
    public Object get(int index) {
        if (!statisticCalculated) {
            calculateStatistic();
            statisticCalculated = true;
        }

        //Style holen
        TextStyle tmpStyle = (TextStyle) super.get(index);

        //Gewicht setzen
        tmpStyle.weight = styleMatrix[tmpStyle.style];

        return tmpStyle;
    }

    /**
     * Liefert die Anzahl der gespeicherten Styles zurück.
     */
    public int size() {
        return super.size();
    }
}
