//========================================================================
// Copyright(C): RFAI France
//
// CLR Version : 4.0.30319.18052
// NameSpace : Matching
// FileName : IndexGraph.cs
//
// Created by : JC (jiangchar@gamil.com) at 1/1/2014 10:04:19 PM
//
//========================================================================
#region Using directives

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Graphs;
using System.IO;
using Accord.MachineLearning;
using System.Xml;

#endregion

namespace Matching
{
    public class IndexGraph
    {
        /***************************************************************/
        /*************************Attributs*****************************/
        /***************************************************************/

        #region Attributs

        //la signature qui contient tout les cliques de base de graphe
        FMGESignature signature;

        //cluster information, pour la phase de recherche
        ClusterInformation clusterInfo;

        int intSuccessCount = 0, intAllCount = 0;

        #endregion

        /***************************************************************/
        /*************************Accesseurs****************************/
        /***************************************************************/

        #region Accesseurs

        public FMGESignature GetFGMEsignature
        {
            get { return signature; }
            set { signature = value; }
        }

        public int IntSuccessCount
        {
            get { return intSuccessCount; }
            set { intSuccessCount = value; }
        }

        public int IntAllCount
        {
            get { return intAllCount; }
            set { intAllCount = value; }
        }
        #endregion

        /***************************************************************/
        /************************Constructeurs**************************/
        /***************************************************************/

        #region Constructeurs

        public IndexGraph()
        {
            clusterInfo = new ClusterInformation();
        }

        #endregion

        /***************************************************************/
        /*********************Méthodes publics**************************/
        /***************************************************************/

        #region Méthodes publics

        /// <summary>
        /// La méthode principale
        /// </summary>
        /// <param name="StrDirectory">Le répertoire du graphe à ajouter</param>
        /// <param name="levelGraph">s'il contient du graph level information</param>
        /// <param name="levelStructure">s'il contient du structure level information</param>
        /// <param name="levelComponent">s'il contient du elementary level information</param>
        /// <param name="nbClass">le nombre de classe</param>
        /// <param name="threshold">le parametre de la méthode clustering</param>
        public void Run(string StrDirectory, bool levelGraph = true, bool levelStructure = true,
            bool levelComponent = true, int nbClass = 3, double threshold = 0.00001)
        {
            signature = new FMGESignature(StrDirectory);
            DirectoryInfo DirRun_CurrentDir;
            try
            {
                DirRun_CurrentDir = new DirectoryInfo(StrDirectory);
            }
            catch (Exception e)
            {
                Console.Write(e.Message);
                throw new Exception("choose a directory \n", e);
            }
            FileInfo[] FilRun_CurrentFile = DirRun_CurrentDir.GetFiles();
            foreach (FileInfo NextFile in FilRun_CurrentFile)  //pour tous les fichiers dans ce répertoire
            {
                intAllCount += 1;
                //---------------------------------------------------------------------------------------
                //--------------------------------parcourrir les fichiers---------------------------------
                //---------------------------------------------------------------------------------------
                try
                {
                    //seulement pour les fichiers gxl.
                    if (String.Compare(NextFile.Extension, ".gxl", true) == 0)
                    {
                        AddGraph(StrDirectory + "\\" + NextFile, NextFile.Name);
                        intSuccessCount += 1;
                    }
                }
                catch (Exception e)
                {
                    Console.Write(e.Message);
                    throw new Exception("Fail to add graph into signature \n", e);
                }
            }
            //---------------------------------------------------------------------------------------
            //si dans ce répertoire, il n'y a pas de fichier gxl
            if (intSuccessCount == 0)
            {
                Console.Write("There isn't any fichier gxl \n");
                return;
            }

            //---------------------------------------------------------------------------------------
            //--------------------------------Embedding----------------------------------------------
            //---------------------------------------------------------------------------------------
            try
            {
                signature.FillTable(levelGraph, levelStructure, levelComponent, FMGESignature.LearnBins, "");
            }
            catch (Exception e)
            {
                Console.Write(e.Message);
                throw new Exception("fail to get vectors", e);
            }

            //---------------------------------------------------------------------------------------
            //--------------------------------Clustering---------------------------------------------
            //---------------------------------------------------------------------------------------
            Clustering(nbClass, threshold);
            //---------------------------------------------------------------------------------------
            //--------------------------------stocke ClusterInfo-------------------------------------
            //---------------------------------------------------------------------------------------

        }
        //--------------------------------------fin de Run-----------------------------------------------

        /// <summary>
        /// Ajouter des cliques d'un graphe dans le contenu de la signature.
        /// </summary>
        /// <param name="StrDirectory">Le répertoire du graphe à ajouter</param>
        /// <param name="StrName">Le nom du graphe à ajouter</param>
        public void AddGraph(string StrDirectory, string StrName)
        {
            //Graphe temporaire pour stocker le graphe dans un fichier GXL
            Graph GraAddInd_tmp = new Graph();

            //essaie de lire le fichier GXl
            try
            {
                GraAddInd_tmp.loadGXL(StrDirectory);
            }
            catch(Exception e)
            {
                Console.Write(e.Message);
                throw new Exception("fail to load GXL file- " + StrName + "\n", e);
            }

            try
            {
                //calcule les cliques dans un graphe et les stocke dans l'objet de FGMESignqture
                signature.ExtractClique(GraAddInd_tmp, StrName, false);
            }
            catch (Exception e)
            {
                Console.Write(e.Message);
                throw new Exception("fail to extrait clique from this graph " + StrName + " in " + StrDirectory + "\n", e);
            }
        }
        //--------------------------------------fin de AddGraph-----------------------------------------

        /// <summary>
        /// Stocker le fichier XML
        /// </summary>
        /// <param name="StrDictionary">Le répertoire du fichier XML</param>
        public void WriteXML(string StrDictionary)
        {
            signature.WriteXML(StrDictionary);
        }
        //--------------------------------------fin de WriteXML-----------------------------------------

        /// <summary>
        /// voir le resultat de clustering et le sortir en forme de XML
        /// </summary>
        /// <param name="StrDictionary"></param>
        public void TestClustering(string StrDictionary)
        {
            clusterInfo.SaveAsXML(StrDictionary);
            //ClusterInformation s = new ClusterInformation();
            //s.ReadFromXML(StrDictionary);
        }

        #endregion

        /***************************************************************/
        /*********************Méthodes privées**************************/
        /***************************************************************/

        #region Méthodes privées

        /// <summary>
        /// Clustering K-means utilisé la biblothètique Alglib
        /// </summary>
        /// <param name="nbClass">La nombre de classe</param>
        /// <param name="threshold">La paramètre de la méthode clustering</param>
        private void Clustering(int nbClass, double threshold)
        {
            // Create a new K-Means algorithm with 3 clusters 
            KMeans kmeans = new KMeans(nbClass);
            //---------------------------------------------------------------------------------------
            //--------------------------------Convertir pour clustering------------------------------
            //---------------------------------------------------------------------------------------
            List<double[]> LisCluInd_WaitForConvert = new List<double[]>();

            foreach (VectorFMGE v in signature.ListVectorFGME)
            {
                LisCluInd_WaitForConvert.Add(v.GetMatrix());
            }
            double[][] LisCluInd_WaitForCluster = LisCluInd_WaitForConvert.ToArray();
            //---------------------------------------------------------------------------------------
            //--------------------------------Clustering---------------------------------------------
            //---------------------------------------------------------------------------------------
            int[] labels;
            try
            {
                // Compute the algorithm, retrieving an integer array 
                //  containing the labels for each of the observations 
                labels = kmeans.Compute(LisCluInd_WaitForCluster, threshold);
            }
            catch (Exception e)
            {
                Console.Write(e.Message);
                throw new Exception("clustering error, verify your graph base is comparable. \n", e);
            }

            //---------------------------------------------------------------------------------------
            //--------------------------------mis à jour label---------------------------------------
            //---------------------------------------------------------------------------------------
            for (int i = 0; i < labels.Length; i++)
            {
                signature.ListLabel.Add(labels[i]);
            }
            //---------------------------------------------------------------------------------------
            //--------------------------------remplir ClusterInfo------------------------------------
            //---------------------------------------------------------------------------------------
            for (int i = 0; i < kmeans.Clusters.Count; i++)
            {
                VectorFMGE VecCluInd_tmp = new VectorFMGE();

                int name = 0;

                foreach (double d in kmeans.Clusters[i].Mean)
                {
                    VecCluInd_tmp.FSMFV.Add(name.ToString(), d);
                    name += 1;
                }

                clusterInfo.ListCenter.Add(VecCluInd_tmp);
                clusterInfo.ListClusterLabel.Add(kmeans.Clusters[i].Index);
                clusterInfo.ListCliques.Add(new List<string>());
            }

            for (int i = 0; i < signature.ListLabel.Count; i++)
            {
                for (int j = 0; j < clusterInfo.ListClusterLabel.Count; j++)
                {
                    if (signature.ListLabel[i] == clusterInfo.ListClusterLabel[j])
                    {
                        clusterInfo.ListCliques[j].Add(signature.ListGraphName[i]);
                    }
                }
            }

        }
        //--------------------------------------fin de Clustering---------------------------------------
        #endregion
    }
}
