using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Graphs;
using Matching;
using System.Windows.Forms;

namespace Matching
{
    public unsafe class Glpk_Inexact_Solve : Glpk_Solver,IGraphMatching
    {

        private static Graphs.Label nodeepslabel;
        private string resulttext;

        public Glpk_Inexact_Solve()
        {

        }

        public Glpk_Inexact_Solve(Graph G1, Graph G2, string ResultText): base(G1,G2,ResultText)
        {
            ResultText+="\nInexact Isomorphism\n";
            glp_set_prob_name(lp, "Inexact Isomorphism");
            
        }
        //override the abstract function of the abstract class Glpk_Solver
        public override void constractProblem()
        {
            //for storing the value of the constraint matrix
            List<int> iaList = new List<int>();
            List<int> jaList = new List<int>();
            List<double> arList = new List<double>();
            iaList.Add(0);
            jaList.Add(0);
            arList.Add(0);

            int rownum = 0;
            int colnum = 0;

            int numNodes1 = g1.ListNodes.Count();
            int numNodes2 = g2.ListNodes.Count();
            int numEdges1 = g1.ListEdges.Count();
            int numEdges2 = g2.ListEdges.Count();
           
            //construct the objet funcion and the contraints.
            //the objet funcion
            for (int i = 1; i <= numNodes1; i++)
            {
                for (int k = 1; k <= numNodes2; k++)
                {
                    glp_add_cols(lp, 1);
                    ++colnum;
                    glp_set_col_kind(lp, colnum, GLP_BV);
                    glp_set_col_name(lp, colnum, ("x_" + g1.ListNodes[i - 1].Id + "," + g2.ListNodes[k - 1].Id));
                    glp_set_obj_coef(lp, colnum, g1.ListNodes[i - 1].Label.dissimilarity(g2.ListNodes[k - 1].Label));

                }
            }

            for (int ij = 1; ij <= numEdges1; ij++)
                for (int kl = 1; kl <= numEdges2; kl++)
                {
                    glp_add_cols(lp, 1);
                    glp_set_col_name(lp, ++colnum, ("y_" + g1.ListEdges[ij - 1].Id + "," + g2.ListEdges[kl - 1].Id));
                    glp_set_col_kind(lp, colnum, GLP_BV);
                    glp_set_obj_coef(lp, colnum, g1.ListEdges[ij - 1].Label.dissimilarity(g2.ListEdges[kl - 1].Label));

                }
            for (int i = 1; i <= numNodes1; i++)
            {
                glp_add_cols(lp, 1);
                ++colnum;
                glp_set_col_kind(lp, colnum, GLP_BV);
                glp_set_col_name(lp, colnum, ("u_" + g1.ListNodes[i - 1].Id));           

                Type typeLabel = g1.ListNodes[i - 1].Label.GetType();
                object obj = Activator.CreateInstance(typeLabel);
                nodeepslabel =(Graphs.Label)obj;
                nodeepslabel.Id = ConstantsAC.EPS_ID;

                glp_set_obj_coef(lp, colnum, ((Graphs.Label)g1.ListNodes[i - 1].Label).dissimilarity(nodeepslabel));
            }

            for (int ij = 1; ij <= numEdges1; ij++)
            {
                glp_add_cols(lp, 1);
                glp_set_col_name(lp, ++colnum, ("e_" + g1.ListEdges[ij - 1].Id));
                glp_set_col_kind(lp, colnum, GLP_BV);

                Type typeLabel = g1.ListEdges[ij - 1].Label.GetType();
                object obj = Activator.CreateInstance(typeLabel);
                nodeepslabel = (Graphs.Label)obj;
                nodeepslabel.Id = ConstantsAC.EPS_ID;
                glp_set_obj_coef(lp, colnum, ((Graphs.Label)g1.ListEdges[ij - 1].Label).dissimilarity(nodeepslabel));
            }
            glp_create_index(lp);


            // contraint: equation 19
            for (int i = 1; i <= numNodes1; i++)
            {
                glp_add_rows(lp, 1);
                glp_set_row_name(lp, ++rownum, "equation19_" + rownum);
                glp_set_row_bnds(lp, rownum, GLP_FX, 1, 1);
                for (int k = 1; k <= numNodes2; k++)
                {
                    iaList.Add(rownum);
                    jaList.Add((i - 1) * numNodes2 + k);
                    arList.Add(1);                    
                }

                iaList.Add(rownum);
                jaList.Add(numNodes1 * numNodes2 + numEdges1*numEdges2 + i);
                arList.Add(1); 
            }


            // equation 20 
            for (int ij = 1; ij <= numEdges1; ij++)
            {
                glp_add_rows(lp, 1);
                glp_set_row_name(lp, ++rownum, "equation20_" + rownum);
                glp_set_row_bnds(lp, rownum, GLP_FX, 1, 1);
                for (int kl = 1; kl <= numEdges2; kl++)
                {

                    iaList.Add(rownum);
                    jaList.Add(numNodes1 * numNodes2 + (ij - 1) * numEdges2 + kl);
                    arList.Add(1);
                }
                iaList.Add(rownum);
                jaList.Add(numNodes1 * numNodes2 + numEdges1 * numEdges2 + numNodes1  + ij);
                arList.Add(1); 
               
            }

            //equation 21 
            for (int k = 1; k <= numNodes2; k++)
            {
                glp_add_rows(lp, 1);
                glp_set_row_name(lp, ++rownum, "equation21_" + rownum);
                glp_set_row_bnds(lp, rownum, GLP_DB, 0, 1);
                for (int i = 1; i <= numNodes1; i++)
                {
                    iaList.Add(rownum);
                    jaList.Add(numNodes2 * (i - 1) + k);
                    arList.Add(1);
                }
            }

            //equation 22 23 24
            
            for(int ij =1; ij<=numEdges1;ij++)
                for (int kl = 1; kl <= numEdges2; kl++)
                {
                    string source_i = g1.ListEdges[ij - 1].NodeSource.Id;
                    string source_k = g2.ListEdges[kl - 1].NodeSource.Id;
                    string target_i = g1.ListEdges[ij - 1].NodeTarget.Id;
                    string target_k = g2.ListEdges[kl - 1].NodeTarget.Id;

                    string nameVar = "x_" + source_i + "," + source_k;
                    int colInd = glp_find_col(lp, nameVar);
                    if (colInd == 0)
                        throw new InvalidProgramException();

                    string nameVar2 = "x_" + target_i + "," + target_k;
                    int colInd2 = glp_find_col(lp, nameVar2);
                    if (colInd2 == 0)
                        throw new InvalidProgramException();

                    glp_add_rows(lp, 1);
                    glp_set_row_bnds(lp, ++rownum, GLP_DB, 0, 1);
                    glp_set_row_name(lp, rownum, "equation22_" + rownum);
                    iaList.Add(rownum);
                    jaList.Add(colInd);
                    arList.Add(1);
                    iaList.Add(rownum);
                    jaList.Add(numNodes1 * numNodes2 + (ij - 1) * numEdges2 + kl);
                    arList.Add(-1);

                    glp_add_rows(lp, 1);
                    glp_set_row_bnds(lp, ++rownum, GLP_DB, 0, 1);
                    glp_set_row_name(lp, rownum, "equation23_" + rownum);
                    iaList.Add(rownum);
                    jaList.Add(colInd2);
                    arList.Add(1);
                    iaList.Add(rownum);
                    jaList.Add(numNodes1 * numNodes2 + (ij - 1) * numEdges2 + kl);
                    arList.Add(-1);

                    glp_add_rows(lp, 1);
                    glp_set_row_bnds(lp, ++rownum, GLP_UP, -1, 1);
                    glp_set_row_name(lp, rownum, "equation24_" + rownum);
                    iaList.Add(rownum);
                    jaList.Add(colInd);
                    arList.Add(1);
                    iaList.Add(rownum);
                    jaList.Add(colInd2);
                    arList.Add(1);
                    iaList.Add(rownum);
                    jaList.Add(numNodes1 * numNodes2 + (ij - 1) * numEdges2 + kl);
                    arList.Add(-1);


                    //testc
                    int a = numNodes1 * numNodes2 +( ij-1 )*numEdges2 + kl;
                    string var = "y_" + g1.ListEdges[ij - 1].Id + "," + g2.ListEdges[kl - 1].Id;
                    int colIndtest = glp_find_col(lp, var);
                    if (colIndtest != a)
                        throw new FieldAccessException("haha test failed");
 
                }
          
            //declare the contraints matrix
            ConstraintMatrix CM = new ConstraintMatrix();
            int numEle = arList.Count() - 1;
            CM.ia = iaList.ToArray();
            CM.ja = jaList.ToArray();
            CM.ar = arList.ToArray();
            glp_load_matrix(lp, numEle, CM.ia, CM.ja, CM.ar);

        }





        public Dictionary<Node, Node> getNodeMatching()
        {
            return this.NodeMatching;
        }

        public double getCost()
        {
            return this.Totalcost;
        }

        public void Compute(Graph g1, Graph g2)
        {
            
            this.init(g1, g2, this.resulttext);
            glp_set_prob_name(lp, "Inexact Isomorphism");
            this.constractProblem();
            this.solve_problem();
           
            List<string[]> nodes  = new List<string[]>();
            this.print_sol(nodes,this.resulttext);
        }

        public bool isOptimal()
        {
            return true;
        }
    }
}

