/*
 * $Id: Clustern.java,v 1.3 2007/10/30 13:52:24 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: Clustern.java,v $
 * Revision 1.3  2007/10/30 13:52:24  marbobo
 * + removed unnecessary statements
 *
 * Revision 1.2  2006/07/31 07:21:16  lawern
 * Überarbeitung
 *
 */
package vkc.clusterer;

import cern.colt.matrix.impl.SparseDoubleMatrix2D;

import vkc.analyse.Analyser;
import vkc.analyse.SummaryEntry;

import vkc.converter.DocConverter;
import vkc.converter.TdfDocConverter;

import vkc.db.entities.VKCAdditionalDocumentFormat;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCDocument;

import vkc.misc.VKCLogManager;

import vkc.server.archive.DataStoreException;

import vkc.util.ClusterUtils;

import java.io.*;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;


public class Clustern {
    public static final boolean SIN_LOWEST_TERMFREQUENCY = true; //Terme mit minimalster Frequenz,(meistens 1) weglassen 
    public static final boolean CLUSTER_UNTIL_THE_END = false; // Clustere bis der Heap leer ist.
    public static final boolean SIN_NUMBERS = false; // Lasse Zahlen aus Dokumenten weg
    public static final boolean OF_MEASURE = false; // Quelitätsmass berechnen
    public static final int STANDARD_WEIGHT = 0;
    public static final int TFIDF_WEIGHT = 1;
    
    public static double log2 = Math.log(2);
    public static final String CLUSTER_MAP_NAME = "clusterMapName";
    public static final String DELIMITER = "-";
    protected static boolean debug = false;
    protected static boolean debugTerm = false;
    public boolean CLUSTER_WITH_TERM_INTERSECTION = false; //Baue Dendogram solange auf, wenn Cluster gemeinsame Terme haben. 
    public int MAX_KEYWORDS = -1;
    protected int anzahlDocs = 0; // N Anzahl der Dokumente in TDM
    protected int nrUnconvertedDocs = 0; // Anzahl unkonvertierter Dokumente
    protected int anzTerme = 0; // M Anzahl der Terme in der TDM wird in Hashmap gesetzt
    protected int gesAnzTerme = 0; // Gesamtzahl aller Wörter (in allen Dokumenten) spielt
    protected int weightingMode = TFIDF_WEIGHT;
    protected int unique_ID = 0; // ID-Generator für Cluster/ VKC-Categories

    // Verwaltet die Ähnlichkeit der Dokumente
    protected IndexHeap indexedHeap = new IndexHeap(0);

    // TermDokumentenMatrix
    protected SparseDoubleMatrix2D tdMatrix; // Speichert die

    // Verwaltet die clusteringDocument-Objecte
    protected Vector vClusterDocuments = new Vector();
    HashMap allTerms = new HashMap(); // Schnittmenge aller Terme aller Dokumente
    HashMap allCluster = new HashMap();
    HashMap originalClassNames = new HashMap();
    HashSet heapIds = new HashSet();
    List documents;

    // nur statistische Rolle
    SummaryEntry[] aSummaryEntry;

    // wird in Clusterutils.java gesetzt
    VKCCategory category;

    //  Constructor
    public Clustern(VKCCategory category, int weightingMode,
        Integer maxKeywords, boolean termIntersection) {
        this.setCategory(category);
        this.weightingMode = weightingMode;

        if (maxKeywords != null) {
            MAX_KEYWORDS = maxKeywords.intValue();
        }

        CLUSTER_WITH_TERM_INTERSECTION = termIntersection;
    }

    // Aufruf in der Klasse ClsuterUtils in der Methode clusterCategory(VKCCategory)
    public final HashMap getCluster() {
        documents = category.getDocuments();
        anzahlDocs = documents.size(); // Grösse N in TDM
        indexedHeap = new IndexHeap((((anzahlDocs * anzahlDocs) + anzahlDocs) / 2) +
                1);

        try {
            prepareDocuments();
            prepareTerms();

            calculateTermWeights();

            // Berechne für jedes Dokument einmalig seine Vectorenlänge
            calculateDocLength();

            // Berechne für alle Cluster die Menge seiner Terme
            prepareClusterTerms();

            // bilde TermdokumenetenMatrix
            if (debug) {
                System.out.println("---buildSparseTDM()");
            }

            buildSparseTDM();

            // Brechne Ähnlichkeit zwischen je zwei Doumentenvektoren und pack
            // es in den Heap
            if (debug) {
                System.out.println("---Aufruf calculCosSimilarity()");
            }

            calculCosSimilarity();

            if (debug) {
                System.out.println("---Aufruf buildClusterFromHeap()");
            }

            buildClusterFromHeap();

            // Für Qualitätsberechnung
            if (OF_MEASURE) {
                parseOriginalClassNames();
                calculOverallFMeasure();
            }

            //viewDendogram();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (debug) {
            System.out.println("Anzahl Dokumente ohne Konvertierung:" +
                nrUnconvertedDocs);
        }

        return allCluster;
    }

    private void calculateTermWeights() {
        if (STANDARD_WEIGHT == weightingMode) {
        } else if (TFIDF_WEIGHT == weightingMode) {
            calculateTFIDFWeight();
        }
    }

    /**
     * Berechnet die Vereinigungsmenge aller Terme in allen Dokumenten,
     * Erzeuge für jeden Term ein Object TermEntry
     */
    private void prepareTerms() {
        int size = vClusterDocuments.size();

        for (int i = 0; i < size; i++) {
            ClusteringDocument c = (ClusteringDocument) vClusterDocuments.get(i);
            SummaryEntry[] se = c.getVDocTerms();
            SummaryEntry[] nse = new SummaryEntry[0];

            if (debugTerm) {
                System.out.println("");
                System.out.println("Document-Titel: " + c.getDocumentTitel());
            }

            if (se != null) {
                if (SIN_LOWEST_TERMFREQUENCY) {
                    for (int k = se.length - 1; k >= 0; k--) {
                        if (k > 0) {
                            if ((se[k - 1].getWeight() - se[k].getWeight()) > 0) {
                                nse = new SummaryEntry[k];
                                System.arraycopy(se, 0, nse, 0, k);

                                break;
                            }
                        }
                    }

                    if (nse.length > 0) {
                        se = nse;
                    }
                }

                for (int j = 0; j < se.length; j++) {
                    String keyWord = se[j].getText();

                    if (SIN_NUMBERS) {
                        try {
                            Long.valueOf(keyWord);

                            continue; // next Step in Loop
                        } catch (NumberFormatException e) {
                        }
                    }

                    TermEntry aTerm = new TermEntry();
                    aTerm.setTerm(keyWord);
                    aTerm.setTermWeight(se[j].getWeight()); // setze Gewicht auf standardWeight
                    aTerm.getDocumentIds().add(c.getDocumentId()); // update Liste der Dokumente, die diesen Term enthalten
                    c.getTermEntries().add(aTerm); // Füge Term in die TermListe des clusteriungDocuments ein.

                    TermEntry term = (TermEntry) allTerms.get(keyWord);

                    if (term != null) {
                        // Term  war schon mal da 
                        term.getDocumentIds().add(c.getDocumentId()); // Merke, in welchem Dokument der Term dieses mal vorkommt
                        aTerm.getDocumentIds().addAll(term.getDocumentIds()); //Merke für den neuen TermEntry, wo er schon mal vorgekommen ist 
                        aTerm.setTermIndex(term.getTermIndex()); // der Term hat schon einen Term-Index.

                        if (debugTerm) {
                            System.out.print("---Wiederholter Term: " +
                                keyWord);
                        }
                    } else {
                        // Term ist neu => index merken und in hashMap einfügen
                        //Berechne für jeden neuen Term den Index
                        aTerm.setTermIndex(anzTerme++);
                        allTerms.put(keyWord, aTerm);

                        if (debugTerm) {
                            System.out.print("--" + keyWord);
                        }
                    }
                }
            }
        }

        if (debugTerm) {
            System.out.println("");
            System.out.println("----------------------------------------------");
        }
    }

    /**
     * initialisiert die notwendigen Datenstrukturen für Clustering
     */
    private void prepareDocuments() {
        //    erzeuge root-Cluster
        ClusteringItem rootCluster = new ClusteringItem();
        rootCluster.setClusterID(new Integer(-1));
        rootCluster.setHeapID(new Integer(-1));
        rootCluster.setRecursivDocCounts(anzahlDocs);
        rootCluster.setName(category.getName());
        allCluster.put(rootCluster.getClusterID(), rootCluster);

        // Cluster, der am Anfang alle N Cluster enthält. Hängt am root
        ClusteringItem beginCluster = new ClusteringItem();
        beginCluster.setClusterID(new Integer(unique_ID++));
        beginCluster.setHeapID(beginCluster.getClusterID());
        beginCluster.setParentID(rootCluster.getClusterID());
        beginCluster.setRecursivDocCounts(anzahlDocs);
        beginCluster.setName("Misc");
        rootCluster.addSubCluster(beginCluster.getClusterID());
        allCluster.put(beginCluster.getClusterID(), beginCluster);

        for (int i = 0; i < anzahlDocs; i++) {
            // hole jedes VKCDokument aus der Liste
            VKCDocument document = (VKCDocument) documents.get(i);

            ClusteringDocument clusteringDocument = new ClusteringDocument();
            ClusteringItem clusteringItem = new ClusteringItem();

            // setze ClusterId. Im schritt Null Nummerierung der ClusteringItems
            // [1 ... N]
            clusteringItem.setClusterID(new Integer(unique_ID++));
            clusteringItem.setHeapID(clusteringItem.getClusterID());

            // Hole die Keywords aus der VKCDokument
            SummaryEntry[] vDocTerms = getKeyWords(document);

            beginCluster.getRecursivDocumentIds().add(document.getDocumentId());

            if (vDocTerms != null) {
                // benötigt für Iteration über alle Cluster
                heapIds.add(clusteringItem.getClusterID());

                // hole Terme eines Dokuments
                clusteringDocument.setVDocTerrms(vDocTerms);

                // Setze VKCDocumentID
                clusteringDocument.setDocumentId(document.getDocumentId());

                // Setze VKCDocumentTitel
                clusteringDocument.setDocumentTitel(document.getName());

                // Füge VKCDocumentID ein.
                clusteringItem.addDocumentId(document.getDocumentId());
                clusteringItem.getRecursivDocumentIds()
                              .add(document.getDocumentId());
                clusteringItem.setRecursivDocCounts(1);

                //Am Anfang N Ein-Elementige Cluster hängen am beginCluster mit der ID==0
                clusteringItem.setParentID(beginCluster.getClusterID());
                beginCluster.addSubCluster(clusteringItem.getClusterID());

                clusteringDocument.setClusterID(clusteringItem.getClusterID());
                clusteringDocument.setVDocTerrms(vDocTerms);
                clusteringItem.getDocuments().add(clusteringDocument);

                // Füge nur converiete Dokumente in den Verwaltungsvektor 
                vClusterDocuments.add(clusteringDocument);

                //vClusteringItems.add(i,clusteringItem);
                allCluster.put(clusteringItem.getClusterID(), clusteringItem);
            } else {
                if (debug) {
                    System.out.println("Dokument ohne Konvertierung gefunden!");
                }

                nrUnconvertedDocs++;

                //Setze VKCDocumentID
                clusteringDocument.setDocumentId(document.getDocumentId());

                // Setze VKCDocumentTitel
                clusteringDocument.setDocumentTitel(document.getName());

                // Füge VKCDocumentID ein. Am Anfang N Ein-Elementige Cluster
                clusteringItem.addDocumentId(document.getDocumentId());
                clusteringItem.getRecursivDocumentIds()
                              .add(document.getDocumentId());
                clusteringItem.setRecursivDocCounts(1);

                clusteringItem.setParentID(beginCluster.getClusterID());
                beginCluster.addSubCluster(clusteringItem.getClusterID());

                clusteringDocument.setClusterID(clusteringItem.getClusterID());
                clusteringDocument.setVDocTerrms(vDocTerms);

                clusteringItem.getDocuments().add(clusteringDocument);

                //vClusterDocuments.add(i, clusteringDocument);
                allCluster.put(clusteringItem.getClusterID(), clusteringItem);
            }
        }
    }

    // bildet sparseTDM
    // brechnet für jeden Term einen Index durch HashMap hashEntry
    private void buildSparseTDM() {
        double weight;
        int size = vClusterDocuments.size();

        // Lege TDM an. Erst hier möglich da M und N bekannt sein müssen
        // anzahl Terme wird aus der votedList.length bestimmt
        tdMatrix = new SparseDoubleMatrix2D(size, anzTerme);

        // Iterieren über Einträge in vDocTermsWeight(entspricht Zeilen TDM)
        for (int i = 0; i < size; i++) {
            ClusteringDocument c = (ClusteringDocument) vClusterDocuments.get(i);

            for (Iterator iter = c.getTermEntries().iterator(); iter.hasNext();) {
                TermEntry t = (TermEntry) iter.next();
                // Abfrage is Term in votedList enthalten, dann füge in TDM ein.
                weight = t.getTermWeight();

                int row = i;
                int column = t.getTermIndex();

                // Füge Gewicht in der Zeile berechnet aus dem Index
                if (debug) {
                    System.out.println(t.getTermIndex() + ",");
                }

                // O(1) für get, getQuick, set, setQuick and size
                tdMatrix.setQuick(row, column, weight);
            }
        }

        int cardTDM = tdMatrix.cardinality();

        if (debug) {
            System.out.println(" --->Kardinalität der TDM: " + cardTDM);
            System.out.println(
                "--->Anzahl der Terme -ohne hashMap- aus allen Dokumenten  gesAnzTerme" +
                gesAnzTerme);
            System.out.println("--->Anzahl der Terme in hashMap anzTerme " +
                allTerms.size());
        }
    }

    //Berechene für alle Dokumentenvektoren einmalig die Länge
    private void calculateDocLength() {
        double valueVectorX = 0.0;
        double quadratX = 0.0;
        double sqrtX = 0.0;
        int size = vClusterDocuments.size();

        for (int i = 0; i < size; i++) {
            ClusteringDocument c = (ClusteringDocument) vClusterDocuments.get(i);

            for (Iterator iter = c.getTermEntries().iterator(); iter.hasNext();) {
                TermEntry t = (TermEntry) iter.next();

                gesAnzTerme++; // für die Statistik
                valueVectorX = t.getTermWeight();

                if ((valueVectorX != 0.0)) {
                    //Berechne (x[0]^2 + x[1]^2 + ...)
                    quadratX += (valueVectorX * valueVectorX);
                }
            }

            //Brechne sqrt(x[0]^2 + x[1]^2 + ...)
            sqrtX = Math.sqrt(quadratX);
            c.setDocVectorlength(sqrtX);
        }
    }

    // Berechene für alle Cluster die Menge seiner Terme
    private void prepareClusterTerms() {
        for (Iterator iter = allCluster.values().iterator(); iter.hasNext();) {
            ClusteringItem c = (ClusteringItem) iter.next();

            for (Iterator it = c.getDocuments().iterator(); it.hasNext();) {
                ClusteringDocument d = (ClusteringDocument) it.next();

                c.getTerms().addAll(d.getTermEntries());
            }
        }
    }

    //Brechnet die Ähnlichkeit zwischen allen Dokumentenpaaren( obere
    // Dreiecksmatrix)
    // Fügt die Werte in Heap ein.
    private void calculCosSimilarity() {
        //am 26.4.2005 getestet. Liefert richtige Ergebnisse
        int rowTDM = tdMatrix.rows();
        int colTDM = tdMatrix.columns();
        double valueVectorX = 0.0;
        double valueVectorZ = 0.0;
        double similValue = 0.0;
        double scalarParoduktXZ = 0.0; // entspricht dem Zähler der Formel
                                       //Berechene für alle Dokumentenvektoren das Skalarprodukt
                                       // Sum(x[i]*y[i])

        for (int i = 0; i < (rowTDM - 1); i++) {
            //for (int i = rowTDM -1; i >= 0 ; --i) {
            //scalarParoduktXY= 0.0;
            for (int z = i + 1; z < rowTDM; z++) {
                scalarParoduktXZ = 0.0;

                // Schleife Berechne Scalarprodukt Sum(x[i]*y[i])
                for (int j = 0; j < colTDM; j++) {
                    //for (int j= colTDM -1 ; j >= 0; --j){
                    valueVectorX = tdMatrix.getQuick(i, j);
                    valueVectorZ = tdMatrix.getQuick(z, j);

                    if ((valueVectorX != 0) && (valueVectorZ != 0)) {
                        scalarParoduktXZ += (valueVectorX * valueVectorZ);
                    }
                }

                if (debug) {
                    System.out.println(" Sum(x[i]*y[i]) (" + i + ", " + z +
                        ") : " + scalarParoduktXZ);
                }

                // Berechne das Cosinunsmass für zwei Vektoren Doc1 und Doc2
                ClusteringDocument erstesElement = (ClusteringDocument) vClusterDocuments.get(i);
                ClusteringDocument zweitesElement = (ClusteringDocument) vClusterDocuments.get(z);

                if ((erstesElement != null) && (zweitesElement != null)) {
                    //if (erstesElement.isConverted() && zweitesElement.isConverted()) {
                    if ((erstesElement.getDocVectorlength() != 0.0) &&
                            (zweitesElement.getDocVectorlength() != 0.0)) {
                        similValue = scalarParoduktXZ / (erstesElement.getDocVectorlength() * zweitesElement.getDocVectorlength());

                        //System.out.println(" --->Sim Linkes-ClusterID, Rechtes Cluster-ID: " + erstesElement.getClusterID().intValue() + " " + zweitesElement.getClusterID().intValue() + " " + similValue);
                        // Zu langsam ersetzen durch Buffer
                        //resultfile.write("Sim LinkesClusterID Rechtes Cluster-ID:"+ erstesElement.getClusterID().intValue() + " "+ zweitesElement.getClusterID().intValue()+ " " + similValue+ "\r\n");

                        //Werte in IndexedHeap eingefügen
                        // Achtung: in dieser Phase stimmen noch die HeapIds mit CluserIds überein. Das wird sich aber im Laufe des Programs ändern
                        HeapEntry insertNode = new HeapEntry(erstesElement.getClusterID(),
                                zweitesElement.getClusterID(),
                                erstesElement.getClusterID(),
                                zweitesElement.getClusterID(), similValue);
                        indexedHeap.insert(insertNode.getHeapIndex(), insertNode);
                    }

                    //}
                }
            }
        }
    }

    private void buildClusterFromHeap() {
        if (debug) {
            System.out.println(" ## Beginn  Infos über PQ ##");
            System.out.println(" PQgrösse:" + indexedHeap.getSize());
        }

        int size = vClusterDocuments.size();
        boolean execute = true;

        for (int step = 0; step < size; step++) {
            if (!indexedHeap.isEmpty()) {
                // Entferne die Wurzel vom Heap und bilde Cluster aus den
                // Elementen
                HeapEntry hp = (HeapEntry) indexedHeap.delMax();

                if (CLUSTER_UNTIL_THE_END) {
                    execute = true;
                } else {
                    if (hp.getSim() != 0.0) {
                        execute = true;
                    } else {
                        execute = false;
                    }
                }

                if (execute) {
                    pairCluster(hp);
                }
            } else {
                if (debug) {
                    System.out.println(" ## PQ im Schritt: " + step + "leer");
                }

                //break;
            }
        }
    }

    /**
     * TDFIDF von Term k in Dokument i = (Frequenz von Term k in Dokument i) * IDF von Term k
     * Annnahme: (Frequenz von Term k in Dokument i) wird als Gewichtung aus der Analyser übergeben.
     * Parametereinstellung mit Lars bespechen.
     */
    private void calculateTFIDFWeight() {
        int nrDocs = vClusterDocuments.size();
        double tmpWeight = 0.0;

        for (int i = 0; i < nrDocs; i++) {
            ClusteringDocument c = (ClusteringDocument) vClusterDocuments.get(i);

            for (Iterator iter = c.getTermEntries().iterator(); iter.hasNext();) {
                TermEntry t = (TermEntry) iter.next();
                tmpWeight = t.getTermWeight();
                //                tmpWeight = tmpWeight * ((Math.log(nrDocs) / log2) -
                //                    (Math.log(t.getDocumentIds().size()) / log2) + 1);
                tmpWeight = (tmpWeight * Math.log((nrDocs / t.getDocumentIds()
                                                             .size()) + 1)) / log2;
                t.setTermWeight(tmpWeight);
            }
        }

        //hier müsste die sortierte votedList gefüllt werden.
    }

    protected void pairCluster(HeapEntry hE) {
        // wird jeweils in den abgeleiteten Klasse implementiert
    }

    public final SummaryEntry[] getKeyWords(VKCDocument currDoc) {
        //TDF-Stream holen
        Collection addFormats = currDoc.getAdditionalDocumentFormats();
        VKCAdditionalDocumentFormat currFormat;
        VKCAdditionalDocumentFormat tdfFormat = null;

        for (Iterator formatIt = addFormats.iterator(); formatIt.hasNext();) {
            currFormat = (VKCAdditionalDocumentFormat) formatIt.next();

            if (debug) {
                System.out.println("TDF-Format: " + DocConverter.tdf);
            }

            if (currFormat.getDocTypeId()
                              .compareTo(new Integer(DocConverter.tdf)) == 0) {
                tdfFormat = currFormat;

                break;
            }
        }

        InputStream tdfStream = null;

        if (tdfFormat != null) {
            try {
                tdfStream = tdfFormat.getInputStream();
            } catch (DataStoreException e) {
                VKCLogManager.errorLog(ClusterUtils.class,
                    " getInputStream fehlgeschlagen!", "2", e);
            }
        }

        if (tdfStream == null) {
            if (debug) {
                System.out.println("kein TDFStream: " +
                    currDoc.getDocumentId().intValue());
            }

            return null;
        }

        //Keywords aus der TDF-Datei holen
        TdfDocConverter converter = new TdfDocConverter();

        try {
            converter.convert(tdfStream, null);
        } catch (Exception e) {
            //System.out.println("kein Converter:" + currDocId.intValue());
            VKCLogManager.errorLog(ClusterUtils.class,
                " kein Converter:" + currDoc.getDocumentId().intValue(), "3", e);

            return null;
        }

        Analyser analyser = Analyser.createAnalyser(converter.getElements());

        if (analyser == null) {
            if (debug) {
                System.out.println("kein Analyser:" +
                    currDoc.getDocumentId().intValue());
            }

            return null;
        }

        // hole die Top 20 KeyWords
        SummaryEntry[] keys = analyser.getKeyWords(MAX_KEYWORDS);

        return keys;
    }

    /**
     * @return Returns the category.
     */
    public VKCCategory getCategory() {
        return category;
    }

    /**
     * @param category The category to set.
     */
    public void setCategory(VKCCategory category) {
        this.category = category;
    }

    public int getHeapIndex(int c1, int c2) {
        return (c1 > c2) ? ((((c1 * (c1 + 1)) / 2) + c2) - c1)
                         : ((((c2 * (c2 + 1)) / 2) + c1) - c2);
    }

    private void calculOverallFMeasure() {
        double overallFM = 0.0;

        // Iteration über alle Classen
        for (Iterator it1 = originalClassNames.keySet().iterator();
                it1.hasNext();) {
            String key = (String) it1.next();
            HashSet classDocIds = (HashSet) originalClassNames.get(key);
            double maxFM = 0.0;

            // Itration über alle Cluster
            for (Iterator it2 = allCluster.values().iterator(); it2.hasNext();) {
                ClusteringItem c = (ClusteringItem) it2.next();

                if (!c.getClusterID().equals(new Integer(-1))) {
                    // Berechne Schnittmenge zwischen Class un Cluster
                    HashSet intersection = new HashSet();
                    intersection.addAll(classDocIds);
                    intersection.retainAll(c.getRecursivDocumentIds());

                    // Brechne recall
                    double recall = (double) intersection.size() / (double) classDocIds.size();

                    // Brechne precision
                    double precision = (double) intersection.size() / (double) c.getRecursivDocumentIds()
                                                                                .size();

                    // Berechne F-Measure
                    double fm = (2 * precision * recall) / (precision + recall);

                    if (maxFM < fm) {
                        maxFM = fm;
                    }
                }
            }

            overallFM += (((double) classDocIds.size() / (double) anzahlDocs) * maxFM);
        }

        if (debug) {
            System.out.println("-----------------------------------");
            System.out.println("OVERALL F-MEASURE = " + overallFM);
            System.out.println("-----------------------------------");
        }
    }

    private void parseOriginalClassNames() {
        for (Iterator it = documents.iterator(); it.hasNext();) {
            VKCDocument document = (VKCDocument) it.next();

            int index = document.getName().indexOf(DELIMITER);

            if (index != -1) {
                String key = (document.getName().substring(0, index)).trim();

                HashSet entry = (HashSet) originalClassNames.get(key);

                if (entry != null) {
                    // Class schon mal da
                    entry.add(document.getDocumentId());
                } else {
                    // Class neu
                    entry = new HashSet();
                    entry.add(document.getDocumentId());
                    originalClassNames.put(key, entry);
                }
            }
        }
    }

    //  Berechnet auf der Basis von tdMatrix und BLAS die Ähnlichkeit zwischen
    // jeweils zwei Dokumentenvektoren
    // Vepackt die Ähnlichkeit in HeapEntry und tut sie in PQ rein
    /*
     * private void calculCosSimBlas() { // 309648 ms = 5,16 Min bei 243
     * Dokumenten //SimilarityMeasure cosinusMass = new SimilarityMeasure();
     * Blas linAlg = SeqBlas.seqBlas; //cosinusMass.setTdMatrix(tdMatrix);
     * double numerator; // Zähler des Terms double denumeratorPart1; // Zähler
     * des Terms- Erster Teil double denumeratorPart2; DoubleMatrix1D vDoc1 =
     * null; DoubleMatrix1D vDoc2 = null; double simDoc1Doc2; //SimilarityHeap
     * mySimilarityHeap = new SimilarityHeap(); int docCounter =
     * tdMatrix.rows(); // Zeilen entsprechen den Dokumenten
     * System.out.println("## Brechne Cosinius-Mass-Ähnlichkeiten mit BLAS ##");
     * Berchne die Länge aller Dokumentenvektoren und gebe Sie aus for (int i =
     * 0; i < docCounter ; i++) { vDoc1 = tdMatrix.viewRow(i); // hole erstes
     * Dokument // Berechne die Länge von Doc1 //dnrm2: returns the 2-norm;
     * sqrt(x[0]^2 + x[1]^2 + ...). denumeratorPart1 = linAlg.dnrm2(vDoc1);
     * System.out.println(" Länge von DocVector mit BLAS:" + i + " : " +
     * denumeratorPart1 ); } // Berchne die Summe Xi* Yi aller
     * Dokumentenvektoren und gebe Sie aus
     *
     * for (int i = 0; i < docCounter ; i++) { vDoc1 = tdMatrix.viewRow(i);
     * hole erstes Dokument for (int j = i + 1; j < docCounter; j++) {
     *
     * vDoc2 = tdMatrix.viewRow(j); // hole nächstes Dokument
     *
     * //ddot: returns the dot product of two vectors x and y, which is
     * Sum(x[i]*y[i]). numerator = linAlg.ddot(vDoc1, vDoc2);
     * System.out.println(" Sum(x[i]*y[i]) : " + i + "," + j + "= " +
     * numerator); // Hier müsseen die Werte in ein Indexed Heap eingefügt
     * werden } }
     *
     * for (int i = 0; i < docCounter ; i++) { vDoc1 = tdMatrix.viewRow(i);
     * hole erstes Dokument denumeratorPart1 = linAlg.dnrm2(vDoc1); for (int j =
     * i + 1; j < docCounter; j++) { simDoc1Doc2 = 0.0; vDoc2 =
     * tdMatrix.viewRow(j); // hole nächstes Dokument //simDoc1Doc2 =
     * cosinusMass.calculCosSimilarity(vDoc1, vDoc2); numerator =
     * linAlg.ddot(vDoc1, vDoc2); //ddot: returns the dot product of two vectors
     * x and y, which is Sum(x[i]*y[i]). numerator = linAlg.ddot(vDoc1, vDoc2);
     * denumeratorPart2 = linAlg.dnrm2(vDoc2); simDoc1Doc2 = numerator
     * (denumeratorPart1 * denumeratorPart2); System.out.println(" Sim i,j : " +
     * i + "," + j + "= " + simDoc1Doc2); // Hier müsseen die Werte in ein
     * Indexed Heap eingefügt werden //HeapEntry insertNode = new HeapEntry(i,
     * j, simDoc1Doc2); //myPrioQueue.push(simDoc1Doc2,insertNode);
     * //ausgabePrioQueue(); } }
     *
     *
     * System.out.println("## Ende Berechnung Cosinius-Mass-Ähnlichkeiten mit
     * BLAS##"); }
     */

    //  Gibt Indizes der Elemente in PQ auf dem Monitor aus
    /*
     * private void testIndexPQ(){ System.out.println(" ## Beginn Infos über
     * Indizes in der PQ ##"); System.out.println(" ----- Lösche das Element 0," +
     * (anzahlDocs-1) + "--");
     * myPrioQueue.removeElementAtIdx(myPrioQueue.getIdxOfHeapEntry(new
     * HeapEntry(new Integer(0),new Integer(anzahlDocs-1),0.22222)));
     * System.out.println(" --------- Ausgabe des PQ --"); if (myPrioQueue !=
     * null){ for (int i = 0; i < anzahlDocs - 1; i++) { for (int j = i + 1; j <
     * anzahlDocs; j++) {
     *
     * int idxHeapEntry = myPrioQueue.getIdxOfHeapEntry(new HeapEntry(new
     * Integer (i),new Integer (j),0.22222)); if (idxHeapEntry != -1){
     * System.out.println(" Index für i,j: " + i + "," + j + ": " + idxHeapEntry ); } } } }
     * System.out.println(" ## Ende Infos über Indeizes in der PQ ##"); }
     */
}
