package tr.edu.boun.greenoverlay;

import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumExpr;
import ilog.cplex.IloCplex;
import ilog.cplex.IloCplex.DoubleParam;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.util.Properties;

import tr.edu.boun.greenoverlay.common.GreenOverlayGlobals;
import tr.edu.boun.greenoverlay.common.LinkInfo;
import tr.edu.boun.greenoverlay.common.NodeInfo;
import tr.edu.boun.greenoverlay.common.PathInfo;

/**
 * January 13th, 2012
 * 
 * @author didemgozupek
 * 
 */
public class GreenOverlayMain {

    public static LinkInfo[] readLinkInfo(String filename) {

        // NodeID#1  NodeID#2   uij        W3ij
        LinkInfo[] linkInfoArry = null;
        try {
            FileInputStream fstream;
            if(filename.equals("")){
                String currentDir = new File(".").getCanonicalPath() + "/";
                System.out.println("currentDir:" + currentDir);
    
                fstream = new FileInputStream(currentDir + "/resources/"
                        + GreenOverlayGlobals.linkInfoFileName);
            }
            else{
                fstream = new FileInputStream(filename);
            }

            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;

            strLine = br.readLine();
            GreenOverlayGlobals.numLinks = Integer.parseInt(strLine);
            br.readLine();

            linkInfoArry = new LinkInfo[GreenOverlayGlobals.numLinks];
            for (int i = 0; i < GreenOverlayGlobals.numLinks; i++) {

                linkInfoArry[i] = new LinkInfo();
            }

            for (int iterNum = 0; iterNum < GreenOverlayGlobals.numLinks; iterNum++) {

                strLine = br.readLine();
                String[] strArry = strLine.split(" ");
                linkInfoArry[iterNum].nodeId1 = Integer.parseInt(strArry[0]);
                linkInfoArry[iterNum].nodeId2 = Integer.parseInt(strArry[1]);
                linkInfoArry[iterNum].uijIsOnUnderlay = Integer.parseInt(strArry[2]);
                linkInfoArry[iterNum].w3ijEnergyCost = Double.parseDouble(strArry[3]);
            }

            in.close();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }

        return linkInfoArry;
    }

    public static void main(String[] args) {

        LinkInfo[] linkInfoArray;
        NodeInfo[] nodeInfoArray;
        PathInfo[] pathInfoArray;
        if(args.length != 3){
            linkInfoArray = readLinkInfo("");
            nodeInfoArray = readNodeInfo("");
            pathInfoArray = readPathInfo("");
        }
        else{
            linkInfoArray = readLinkInfo(args[0]);
            nodeInfoArray = readNodeInfo(args[1]);
            pathInfoArray = readPathInfo(args[2]);
        }
       GreenOverlayGlobals.totalRelayCostLimit = GreenOverlayGlobals.numPathPairs;

        GreenOverlayGlobals.inputGraph = new int[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes];

        for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

            for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                GreenOverlayGlobals.inputGraph[i][j] = 0;
            }
        }

        /**
         * Set the t[i] values of the nodes according to the t[i][j] values
         */
    // Alttaki comment out edilen kod: eskiden linklerin sleepable olmas� input olarak al�n�yordu, art�k nodelar�nki al�n�yor
        /*for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

            nodeInfoArray[i].tiCanSleep = 0;
        }

        for (int i = 0; i < GreenOverlayGlobals.numLinks; i++) {

            if (linkInfoArray[i].tijCanSleep == 1) {

                nodeInfoArray[linkInfoArray[i].nodeId1].tiCanSleep = 1; //If at least 1 tij=1, then ti=1
            }
        }*/
        // Linklerin sleepable olmas� nodelara bagl�
        for (int i = 0; i < GreenOverlayGlobals.numLinks; i++) {
            linkInfoArray[i].tijCanSleep = 0;

            if ((nodeInfoArray[linkInfoArray[i].nodeId1].tiCanSleep == 1) || (nodeInfoArray[linkInfoArray[i].nodeId2].tiCanSleep == 1)){
                
                linkInfoArray[i].tijCanSleep = 1; 
            }
        }

        try {

            IloCplex cplex = new IloCplex();
            cplex.setParam(DoubleParam.EpGap, 0.3);

            /**
             * Define the decision variable x[i][j]
             */

            IloIntVar[][] xLink = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes];
            IloIntVar[][] xLinkBar = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes];
            IloIntVar[][] wVertexPath = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];
            IloIntVar[][] mVertexPath = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];
            
            IloIntVar[][] xLinkDirectionless = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes];
            IloIntVar[][] xLinkBarDirectionless = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes];

            IloIntVar[] nVertex = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
            IloIntVar[] nVertexBar = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
            IloIntVar[] zVertex = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                xLink[i] = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
                xLinkBar[i] = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
                xLinkDirectionless[i] = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
                xLinkBarDirectionless[i] = cplex.intVarArray(GreenOverlayGlobals.numNodes, 0, 1);
                wVertexPath[i] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
                mVertexPath[i] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
            }

            /**
             * Define the decision variable x[i][j][p], y[i][j][p], and s[i][j][p]
             */

            IloIntVar[][][] xPath = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];
            IloIntVar[][][] xPathDirectionless = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];
            IloIntVar[][][] yPath = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];
            IloIntVar[][][] sPath = new IloIntVar[GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numNodes][GreenOverlayGlobals.numPathPairs];

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                    xPath[i][j] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
                    xPathDirectionless[i][j] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
                    yPath[i][j] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
                    sPath[i][j] = cplex.intVarArray(GreenOverlayGlobals.numPathPairs, 0, 1);
                }
            }

            IloLinearNumExpr obj = cplex.linearNumExpr();
            IloLinearNumExpr objExpr1 = cplex.linearNumExpr();
            for (int l = 0; l < GreenOverlayGlobals.numLinks; l++) {

                System.out.println("l:" + l);
                
                objExpr1.addTerm(linkInfoArray[l].w3ijEnergyCost,
                                 xLinkDirectionless[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2]);

                GreenOverlayGlobals.inputGraph[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2] = 1;
                GreenOverlayGlobals.inputGraph[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1] = 1;
            }
            obj.add(objExpr1);
            //objExpr1.clear();

            IloLinearNumExpr objExpr2 = cplex.linearNumExpr();

            for (int i = 0; i < GreenOverlayGlobals.numLinks; i++) {
                
                objExpr2.addTerm(linkInfoArray[i].tijCanSleep * linkInfoArray[i].w3ijEnergyCost,
                                 xLinkBarDirectionless[linkInfoArray[i].nodeId1][linkInfoArray[i].nodeId2]);

                GreenOverlayGlobals.inputGraph[linkInfoArray[i].nodeId1][linkInfoArray[i].nodeId2] = 1;
                GreenOverlayGlobals.inputGraph[linkInfoArray[i].nodeId2][linkInfoArray[i].nodeId1] = 1;
            }
            obj.add(objExpr2);
            objExpr2.clear();

            IloLinearNumExpr objExpr3 = cplex.linearNumExpr();
            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                objExpr3.addTerm(nodeInfoArray[i].w2EnergyCost, nVertex[i]);
            }
            obj.add(objExpr3);
            //objExpr3.clear();
            IloLinearNumExpr objExpr4 = cplex.linearNumExpr();
            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                objExpr4.addTerm(nodeInfoArray[i].tiCanSleep * nodeInfoArray[i].w2EnergyCost,
                                 nVertexBar[i]);
            }
            obj.add(objExpr4);
            //objExpr4.clear();
            cplex.addMinimize(obj);
            //obj.clear();
            /**
             * Now the constraints will be added
             */

            IloLinearNumExpr expr1 = cplex.linearNumExpr();

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                    cplex.addLe(xLink[i][j], GreenOverlayGlobals.inputGraph[i][j]); //x[i][j] <= g[i][j]
                    cplex.addGe(xLinkDirectionless[i][j], xLink[i][j]);
                    cplex.addGe(xLinkDirectionless[i][j], xLink[j][i]);
                    IloLinearNumExpr tempExpr = cplex.linearNumExpr();
                    tempExpr.addTerm(1.0, xLink[i][j]);
                    tempExpr.addTerm(1.0, xLink[j][i]);
                    cplex.addLe(xLinkDirectionless[i][j], tempExpr);
                    //tempExpr.clear();
                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                        cplex.addLe(yPath[i][j][p], GreenOverlayGlobals.inputGraph[i][j]);
                        cplex.addLe(sPath[i][j][p], GreenOverlayGlobals.inputGraph[i][j]);
                    }

                    IloNumExpr a = cplex.sum(1, cplex.negative(xLink[i][j]));

                    cplex.addLe(a, xLinkBar[i][j]); //(1-x[i][j]) <= xBar[i][j]

                    cplex.addGe(a, xLinkBar[i][j]); //(1-x[i][j]) >= xBar[i][j]
                    
                    IloNumExpr a2 = cplex.sum(1, cplex.negative(xLinkDirectionless[i][j]));

                    cplex.addLe(a2, xLinkBarDirectionless[i][j]); //(1-x[i][j]) <= xBar[i][j]

                    cplex.addGe(a2, xLinkBarDirectionless[i][j]); //(1-x[i][j]) >= xBar[i][j]

                    cplex.addLe(xLink[i][j], nVertex[i]);//x[i][j] <= n[i] 

                    cplex.addLe(xLink[j][i], nVertex[i]);//x[j][i] <= n[i]

                    expr1.addTerm(1.0, xLink[i][j]);
                    expr1.addTerm(1.0, xLink[j][i]);
                }
            }

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                cplex.addLe(nVertex[i], expr1); //n_i <= \sumi\sumj(x_ij + x_ji)
                //expr1.clear();
                IloNumExpr a = cplex.sum(1, cplex.negative(nVertex[i]));

                cplex.addLe(a, nVertexBar[i]); //(1-n[i]) <= nBar[i]

                cplex.addGe(a, nVertexBar[i]); //(1-n[i]) >= nBar[i]
            }

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                    IloLinearNumExpr expr2 = cplex.linearNumExpr();
                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                        cplex.addLe(xPath[i][j][p], xLink[i][j]); //x[i][j][p] <= x[i][j]
                        expr2.addTerm(1, xPath[i][j][p]);
                    }
                    cplex.addLe(xLink[i][j], expr2); //x[i][j] <= sump_x[i][j][p]
                    //expr2.clear();
                }
            }
            
            // Fatma Start
            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                    IloLinearNumExpr expr2 = cplex.linearNumExpr();
                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                        cplex.addGe(xPathDirectionless[i][j][p], xPath[i][j][p]);
                        cplex.addGe(xPathDirectionless[i][j][p], xPath[j][i][p]);
                        expr2.addTerm(1, xPath[i][j][p]);
                        expr2.addTerm(1, xPath[j][i][p]);
                        cplex.addLe(xPathDirectionless[i][j][p], expr2);
                        //expr2.clear();
                    }
                }
            }
            // Fatma End
           
            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    IloLinearNumExpr expr5 = cplex.linearNumExpr();
                    IloLinearNumExpr expr6 = cplex.linearNumExpr();

                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                        expr5.addTerm(1, xPath[i][j][p]); //sumj_x[i][j][p]
                        expr6.addTerm(1, xPath[j][i][p]); //sumj_x[j][i][p]                      
                    }

                    if (pathInfoArray[p].sourceID == i) {

                        //System.out.println("Source list contains node " + i + " for path " + p);

                        cplex.addLe(expr5, cplex.sum(expr6, 1.0));
                        cplex.addGe(expr5, cplex.sum(expr6, 1.0));
                    } else if (pathInfoArray[p].destID == i) {

                        //System.out.println("Destination list contains node " + i + " for path " + p);

                        cplex.addLe(expr5, cplex.sum(expr6, -1.0));
                        cplex.addGe(expr5, cplex.sum(expr6, -1.0));
                    } else {

                        //System.out.println("Node " + i + " is neither source nor destination" + " for path " + p);
                        cplex.addLe(expr5, expr6);
                        cplex.addGe(expr5, expr6);
                    }
                    //expr5.clear();
                    //expr6.clear();
                }

                for (int l = 0; l < GreenOverlayGlobals.numLinks; l++) {

                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                        IloLinearNumExpr b = cplex.linearNumExpr();
                        IloLinearNumExpr bReverse = cplex.linearNumExpr();

                        /**
                         * u[i][j] <= s[i][j][p]
                         */
                        cplex.addLe(linkInfoArray[l].uijIsOnUnderlay,
                                    sPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);

                        cplex.addLe(linkInfoArray[l].uijIsOnUnderlay,
                                    sPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]);//Do the same thing for both ends of the link

                        for (int p_prime = 0; p_prime < GreenOverlayGlobals.numPathPairs; p_prime++) {

                            if (p != p_prime) {

                                cplex.addLe(xPathDirectionless[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p_prime],
                                            sPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]); //x[i][j][p'] <= s[i][j][p]

                                cplex.addLe(xPathDirectionless[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p_prime],
                                            sPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]); //Do the same thing for both ends of the link

                                b.addTerm(1,
                                          xPathDirectionless[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p_prime]); //sump_prime(x[i][j][p'])

                                bReverse.addTerm(1,
                                                 xPathDirectionless[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p_prime]); //sump_prime(x[i][j][p'])
                            }
                        }

                        IloNumExpr c = cplex.sum(linkInfoArray[l].uijIsOnUnderlay, b);
                        cplex.addLe(sPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p], c); //s[i][j][p] <= u[i][j] + sump_prime(x[i][j][p'])

                        IloNumExpr cReverse = cplex.sum(linkInfoArray[l].uijIsOnUnderlay, bReverse);
                        cplex.addLe(sPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p],
                                    cReverse); //s[i][j][p] <= u[i][j] + sump_prime(x[i][j][p'])

                        //Do the same thing for both ends of the link

                        /**
                         * y[i][j][p] <= x[i][j][p]
                         */
                        cplex.addLe(yPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p],
                                    xPathDirectionless[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);

                        cplex.addLe(yPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p],
                                    xPathDirectionless[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]); //Do the same thing for both ends of the link

                        /**
                         * x[i][j][p] + s[i][j][p] -1  <= y[i][j][p] <= s[i][j][p]
                         */
                        IloNumExpr d = cplex.sum(xPathDirectionless[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p],
                                                 sPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);

                        IloNumExpr e = cplex.sum(d, -1);
                        cplex.addLe(e, yPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);
                        cplex.addLe(yPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p],
                                    sPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);

                        /**
                         * Do the same for both ends of the link
                         */
                        IloNumExpr dReverse = cplex.sum(xPathDirectionless[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p],
                                                        sPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]);

                        IloNumExpr eReverse = cplex.sum(dReverse, -1);
                        cplex.addLe(eReverse,
                                    yPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]);
                        cplex.addLe(yPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p],
                                    sPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]);
                        //b.clear();
                        //bReverse.clear();
                    }
                }

                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    IloLinearNumExpr a = cplex.linearNumExpr();
                    IloLinearNumExpr aReverse = cplex.linearNumExpr();

                    for (int l = 0; l < GreenOverlayGlobals.numLinks; l++) {

                        a.addTerm(1, yPath[linkInfoArray[l].nodeId1][linkInfoArray[l].nodeId2][p]);
                        aReverse.addTerm(1,
                                         yPath[linkInfoArray[l].nodeId2][linkInfoArray[l].nodeId1][p]);
                    }

                    cplex.addLe(a, pathInfoArray[p].kpMaxAllowedOverlap); //\sumi\sumj (y[i][j][p]) <= k_p
                    cplex.addLe(aReverse, pathInfoArray[p].kpMaxAllowedOverlap); //Do the same for both ends of the link
                    //a.clear();
                    //aReverse.clear();
                }
            }

            /**
             * Express m[i][p] in terms of x[i][j][p]
             */

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    IloLinearNumExpr a = cplex.linearNumExpr();
                    IloLinearNumExpr b = cplex.linearNumExpr();
                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                        a.addTerm(1.0, xPath[i][j][p]);
                        b.addTerm(1.0, xPath[j][i][p]);
                    }
                    cplex.addLe(mVertexPath[i][p], a); //m[i][p] <= \sumj x[i][j][p]
                    cplex.addLe(mVertexPath[i][p], b); //m[i][p] <= \sumj x[j][i][p]

                    cplex.addLe(cplex.sum(a, b), cplex.sum(1, mVertexPath[i][p])); // \sumj x[i][j][p] <= m[i][p] + 1 - \sumj x[j][i][p]
                    //a.clear();
                    //b.clear();
                }
            }

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    IloLinearNumExpr mExpr = cplex.linearNumExpr();
                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                        mExpr.addTerm(1.0, xPath[i][j][p]);
                        mExpr.addTerm(1.0, xPath[j][i][p]);
                    }

                    cplex.addGe(mExpr, cplex.prod(2.0, mVertexPath[i][p]));
                    //mExpr.clear();
                }

            }

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                IloLinearNumExpr a = cplex.linearNumExpr();

                for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {

                    a.addTerm(1.0, xLinkDirectionless[i][j]); //z[i] <= sumj(x[i][j])
                }
                cplex.addLe(zVertex[i], a);
                //a.clear();
                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    cplex.addLe(wVertexPath[i][p], zVertex[i]); //w[i][p] <= z[i]
                }
            }

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                    IloNumExpr a = cplex.sum(mVertexPath[i][p], -1);
                    IloNumExpr b = cplex.sum(zVertex[i], a);
                    cplex.addLe(b, wVertexPath[i][p]); //z[i] + m[i][p] -1 <= w[i][p]
                    cplex.addLe(wVertexPath[i][p], mVertexPath[i][p]); //w[i][p] <= m[i][p]
                }
            }

            for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {

                IloLinearNumExpr g = cplex.linearNumExpr();

                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                    if ((pathInfoArray[p].sourceID != i) && (pathInfoArray[p].destID != i)) {

                        g.addTerm(1.0, wVertexPath[i][p]); //sumi w[i][p] = 1
                    }
                }

                cplex.addLe(g, 1.0);
                cplex.addGe(g, 1.0);
                //g.clear();
            }

            IloLinearNumExpr f = cplex.linearNumExpr();

            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                f.addTerm(nodeInfoArray[i].w1RelayCost, zVertex[i]);
            }

            cplex.addLe(f, GreenOverlayGlobals.totalRelayCostLimit);
            //f.clear();

            cplex.solve();

            System.out.println("Solution status = " + cplex.getStatus());
            if (cplex.getStatus() == IloCplex.Status.Infeasible) {

                System.out.println("Infeasible solution");

            } 
            else if (cplex.getStatus() == IloCplex.Status.Optimal) {

                System.out.println("Feasible solution is found");
                System.out.println("Objective fonksiyon " + cplex.getObjValue());
//                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {
//
//                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {
//
//                        for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {
//
//                            System.out.println("xPath[" + i + "][" + j + "][" + p + "]:"
//                                    + cplex.getValue(xPath[i][j][p]));
//                        }
//                    }
//                }
//
//                System.out.println("\n");
//
//                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {
//
//                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {
//
//                        for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {
//
//                            System.out.println("yPath[" + i + "][" + j + "][" + p + "]:"
//                                    + cplex.getValue(yPath[i][j][p]));
//
//                        }
//                    }
//                }

                System.out.println("\n");
                int relayCost = 0;
                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                    //System.out.println("zVertex[" + i + "]:" + cplex.getValue(zVertex[i]));
                    if(cplex.getValue(zVertex[i]) == 1){
                        relayCost++;
                    }
                }
                System.out.println("Relay Cost: " + relayCost);
                System.out.println();

//                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {
//
//                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {
//
//                        System.out.println("wVertexPath[" + i + "][" + p + "]:"
//                                + cplex.getValue(wVertexPath[i][p]));
//                    }
//                }

                System.out.println();

//                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {
//
//                    for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {
//
//                        System.out.println("mVertexPath[" + i + "][" + p + "]:"
//                                + cplex.getValue(mVertexPath[i][p]));
//                    }
//                }
//
//                System.out.println("\n");
//
//                for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {
//
//                    for (int j = 0; j < GreenOverlayGlobals.numNodes; j++) {
//
//                        for (int p = 0; p < GreenOverlayGlobals.numPathPairs; p++) {
//
//                            System.out.println("sPath[" + i + "][" + j + "][" + p + "]:"
//                                    + cplex.getValue(sPath[i][j][p]));
//                        }
//                    }
//                }

            }
            else {

                System.out.println("Some other situation besides (in)feasibility");
            }

            
        } catch (IloException e) {

            e.printStackTrace();
        }

        System.exit(0);
    }

    private static PathInfo[] readPathInfo(String filename) {

        // SourceID#    DestID#   kpMaxAllowedOverlap
        PathInfo[] pathInfoArry = null;
        try {
            FileInputStream fstream;
            if(filename.equals("")){
                String currentDir = new File(".").getCanonicalPath() + "/";
                System.out.println("currentDir:" + currentDir);
    
                fstream = new FileInputStream(currentDir + "/resources/"
                        + GreenOverlayGlobals.pathInfoFileName);
            }
            else{
                fstream = new FileInputStream(filename);
            }
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;

            strLine = br.readLine();
            GreenOverlayGlobals.numPathPairs = Integer.parseInt(strLine);
            br.readLine();

            pathInfoArry = new PathInfo[GreenOverlayGlobals.numPathPairs];
            for (int i = 0; i < GreenOverlayGlobals.numPathPairs; i++) {

                pathInfoArry[i] = new PathInfo();
            }

            for (int iterNum = 0; iterNum < GreenOverlayGlobals.numPathPairs; iterNum++) {

                strLine = br.readLine();
                String[] strArry = strLine.split(" ");
                pathInfoArry[iterNum].sourceID = Integer.parseInt(strArry[0]);
                pathInfoArry[iterNum].destID = Integer.parseInt(strArry[1]);
                pathInfoArry[iterNum].kpMaxAllowedOverlap = Integer.parseInt(strArry[2]);
            }

            in.close();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }

        return pathInfoArry;

    }

    private static NodeInfo[] readNodeInfo(String filename) {

        // #NodeID #w1RelayCost #w2EnergyCost #tiCanSleep
        NodeInfo[] nodeInfoArry = null;
        try {
            FileInputStream fstream;
            if(filename.equals("")){
                String currentDir = new File(".").getCanonicalPath() + "/";
                System.out.println("currentDir:" + currentDir);

                fstream = new FileInputStream(currentDir + "/resources/"
                        + GreenOverlayGlobals.nodeInfoFileName);

            }
            else{
                fstream = new FileInputStream(filename);
            }
           
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;

            strLine = br.readLine();
            GreenOverlayGlobals.numNodes = Integer.parseInt(strLine);
            br.readLine();

            nodeInfoArry = new NodeInfo[GreenOverlayGlobals.numNodes];
            for (int i = 0; i < GreenOverlayGlobals.numNodes; i++) {

                nodeInfoArry[i] = new NodeInfo();
            }

            for (int iterNum = 0; iterNum < GreenOverlayGlobals.numNodes; iterNum++) {

                strLine = br.readLine();
                String[] strArry = strLine.split(" ");
                nodeInfoArry[iterNum].nodeID = Integer.parseInt(strArry[0]);
                nodeInfoArry[iterNum].w1RelayCost = Integer.parseInt(strArry[1]);
                nodeInfoArry[iterNum].w2EnergyCost = Double.parseDouble(strArry[2]);
                nodeInfoArry[iterNum].tiCanSleep = Integer.parseInt(strArry[3]);
            }

            in.close();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }

        return nodeInfoArry;

    }
}
