com.termmed.reconciliation.RelationshipReconciliation.java Source code

Java tutorial

Introduction

Here is the source code for com.termmed.reconciliation.RelationshipReconciliation.java

Source

/**
 * Copyright (c) 2015 TermMed SA
 * Organization
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
package com.termmed.reconciliation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;

import com.termmed.reconciliation.model.Relationship;
import com.termmed.reconciliation.model.RelationshipGroup;
import com.termmed.reconciliation.model.RelationshipGroupList;
import com.termmed.reconciliation.utils.I_Constants;

/**
 * The Class RelationshipReconciliation.
 *
 * @author Alejandro Rodriguez.
 *
 * @version 1.0
 */
public class RelationshipReconciliation {

    /**
     * The main method.
     *
     * @param args the arguments
     */
    public static void main(String[] args) {

        logger = Logger.getLogger("com.termmed.reconciliation.RelationshipReconciliation");
        try {

            File file = new File(I_Constants.RUN_CONFIGURATION_FILE);
            if (!file.exists()) {
                logger.info("Error happened getting params. Params file doesn't exist");
                System.exit(0);
            }

            RelationshipReconciliation cc = new RelationshipReconciliation(file);
            cc.execute();
            cc = null;

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    /** The prev inferred rels. */
    private String[] previousInferredRelationshipsFile;

    /** The temp relationship store. */
    private File tempRelationshipStore;

    /** The config. */
    private File config;

    /** The output relationships. */
    private String outputRelationships;

    /**
     * Instantiates a new classification runner.
     *
     * @param previousInferredRelationships the prev inferred rels
     * @param currentInferredRelationships the output rels
     * @param outputRelationships the output relationship file
     */
    public RelationshipReconciliation(String[] previousInferredRelationships, String[] currentInferredRelationships,
            String outputRelationships) {
        super();

        logger = Logger.getLogger("com.termmed.reconciliation.RelationshipReconciliation");

        this.currentRelationshipsFile = currentInferredRelationships;
        this.previousInferredRelationshipsFile = previousInferredRelationships;

        this.outputRelationships = outputRelationships;
    }

    /**
     * Instantiates a new relationship reconciliation.
     *
     * @param config the config
     * @throws ConfigurationException the configuration exception
     */
    public RelationshipReconciliation(File config) throws ConfigurationException {
        this.config = config;

        logger = Logger.getLogger("com.termmed.reconciliation.RelationshipReconciliation");

        getParams();

    }

    /** The edit snomed rels. */
    private ArrayList<Relationship> previousRelationships;

    /** The logger. */
    private static Logger logger;

    /** The c rocket sno rels. */
    private ArrayList<Relationship> currentRelationships;

    /** The isa. */
    private long isa;

    /** The current relationships file. */
    private String[] currentRelationshipsFile;

    /** The xml config. */
    private XMLConfiguration xmlConfig;

    /** The new no rec. */
    private HashMap<Long, ArrayList<Relationship>> newNoRec;

    /** The prev act now ret. */
    private HashMap<Long, ArrayList<Relationship>> prevActNowRet;

    /** The prev inact. */
    private HashMap<Long, TreeMap<String, Relationship>> prevInact;

    /** The bw. */
    private BufferedWriter bw;

    /** The tmp new no rec. */
    private HashMap<Long, ArrayList<Relationship>> tmpNewNoRec;

    /** The sum b_ total. */
    private int sumB_Total;

    /** The sum same isa. */
    private int sumSameISA;

    /** The sum a_ diff. */
    private int sumA_Diff;

    /** The sum a_ diff isa. */
    private int sumA_DiffISA;

    /** The sum b_ diff. */
    private int sumB_Diff;

    /** The sum b_ diff isa. */
    private int sumB_DiffISA;

    /**
     * Execute the reconciliation.
     */
    public void execute() {

        try {
            sumB_Total = 0;
            sumSameISA = 0;
            sumA_Diff = 0;
            sumA_DiffISA = 0;
            sumB_Diff = 0;
            sumB_DiffISA = 0;

            long startTime = System.currentTimeMillis();
            previousRelationships = new ArrayList<Relationship>();
            prevActNowRet = new HashMap<Long, ArrayList<Relationship>>();
            prevInact = new HashMap<Long, TreeMap<String, Relationship>>();
            newNoRec = new HashMap<Long, ArrayList<Relationship>>();
            tmpNewNoRec = new HashMap<Long, ArrayList<Relationship>>();
            tempRelationshipStore = new File(outputRelationships);
            isa = Long.parseLong(I_Constants.ISA);
            FileOutputStream fos = new FileOutputStream(tempRelationshipStore);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
            bw = new BufferedWriter(osw);

            bw.append("id");
            bw.append("\t");
            bw.append("effectiveTime");
            bw.append("\t");
            bw.append("active");
            bw.append("\t");
            bw.append("moduleId");
            bw.append("\t");
            bw.append("sourceId");
            bw.append("\t");
            bw.append("destinationId");
            bw.append("\t");
            bw.append("relationshipGroup");
            bw.append("\t");
            bw.append("typeId");
            bw.append("\t");
            bw.append("characteristicTypeId");
            bw.append("\t");
            bw.append("modifierId");
            bw.append("\r\n");

            currentRelationships = new ArrayList<Relationship>();

            loadActiveInferredRelationship(currentRelationshipsFile, currentRelationships, 0);

            previousRelationships = new ArrayList<Relationship>();

            loadActiveInferredRelationship(previousInferredRelationshipsFile, previousRelationships, 1);

            groupReassignment(previousRelationships, currentRelationships);

            logger.info(compareActivesAndWriteBack(previousRelationships, currentRelationships));

            previousRelationships = null;
            currentRelationships = null;
            newNoRec = tmpNewNoRec;
            tmpNewNoRec = new HashMap<Long, ArrayList<Relationship>>();

            for (int i = 1; i < 5; i++) {
                if (newNoRec.size() > 0 && prevActNowRet.size() > 0) {

                    logger.info(compareActivesWOMatch(i));
                } else {
                    break;
                }
                newNoRec = tmpNewNoRec;
                tmpNewNoRec = new HashMap<Long, ArrayList<Relationship>>();

            }
            prevActNowRet = null;
            if (newNoRec.size() > 0) {

                loadNotActiveInferredRelationship(previousInferredRelationshipsFile);

                for (int i = 1; i < 5; i++) {
                    if (newNoRec.size() > 0 && prevInact.size() > 0) {

                        logger.info(comparePrevInact(i));
                    } else {
                        break;
                    }
                    newNoRec = tmpNewNoRec;
                    tmpNewNoRec = new HashMap<Long, ArrayList<Relationship>>();
                }
            }
            if (newNoRec.size() > 0) {
                writeNoReconciledRel();
            }
            bw.close();
            bw = null;
            osw = null;
            fos = null;

            StringBuilder s = new StringBuilder();
            s.append("\r\n::: Complete Process statistics:");
            s.append("\r\n::: Reconciled relationships:  \t").append(sumB_Total);
            s.append("\r\n::: Reconciled Isa's relationships:  \t").append(sumSameISA);
            s.append("\r\n::: Previous relationships without match :   \t").append(sumA_Diff);
            //         s.append("\r\n::: Previous Isa's relationships without match:\t").append(sumA_DiffISA);
            s.append("\r\n::: Current relationships without match:   \t").append(sumB_Diff);
            s.append("\r\n::: Current Isa's relationships without match:\t").append(sumB_DiffISA);
            s.append("\r\n::: ");
            s.append("\r\n::: *** WROTE *** LAPSED TIME =\t" + toStringLapseSec(startTime) + "\t ***");
            logger.info(s.toString());

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

    /**
     * Group reassignment.
     *
     * @param snorelA the snorel a
     * @param snorelB the snorel b
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private void groupReassignment(ArrayList<Relationship> snorelA, ArrayList<Relationship> snorelB)
            throws IOException {

        int countChangedGroupNumber = 0;
        long startTime = System.currentTimeMillis();

        StringBuilder s = new StringBuilder();
        s.append("\r\n::: [Start group number reconciliation]");
        Collections.sort(snorelA);
        Collections.sort(snorelB);
        Iterator<Relationship> itA = snorelA.iterator();
        Iterator<Relationship> itB = snorelB.iterator();
        Relationship rel_A = null;
        boolean done_A = false;
        if (itA.hasNext()) {
            rel_A = itA.next();
        } else {
            done_A = true;
        }
        Relationship rel_B = null;
        boolean done_B = false;
        if (itB.hasNext()) {
            rel_B = itB.next();
        } else {
            done_B = true;
        }

        // BY SORT ORDER, LOWER NUMBER ADVANCES FIRST
        while (!done_A && !done_B) {

            if (rel_A.sourceId == rel_B.sourceId) {
                long thisC1 = rel_A.sourceId;
                // REMAINDER LIST_A GROUP 0 FOR C1
                while (rel_A.sourceId == thisC1 && rel_A.group == 0 && !done_A) {

                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                        break;
                    }
                }

                // REMAINDER LIST_B GROUP 0 FOR C1
                while (rel_B.sourceId == thisC1 && rel_B.group == 0 && !done_B) {

                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                        break;
                    }
                }

                // ** SEGMENT GROUPS **
                RelationshipGroupList groupList_A = new RelationshipGroupList();
                RelationshipGroupList groupList_B = new RelationshipGroupList();
                RelationshipGroup groupA = null;
                RelationshipGroup groupB = null;

                // SEGMENT GROUPS IN LIST_A
                int prevGroup = Integer.MIN_VALUE;
                while (rel_A.sourceId == thisC1 && !done_A) {
                    if (rel_A.group != prevGroup) {
                        groupA = new RelationshipGroup();
                        groupList_A.add(groupA);
                    }

                    groupA.add(rel_A);

                    prevGroup = rel_A.group;
                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                    }
                }
                // SEGMENT GROUPS IN LIST_B
                prevGroup = Integer.MIN_VALUE;
                while (rel_B.sourceId == thisC1 && !done_B) {
                    if (rel_B.group != prevGroup) {
                        groupB = new RelationshipGroup();
                        groupList_B.add(groupB);
                    }

                    groupB.add(rel_B);

                    prevGroup = rel_B.group;
                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                    }
                }

                int dist;
                HashMap<Integer, List<Integer[]>> mapGroups = new HashMap<Integer, List<Integer[]>>();
                HashMap<Integer, List<Integer[]>> minDist = new HashMap<Integer, List<Integer[]>>();
                Integer prevRGNum;
                Integer currRGNum;
                if (groupList_B.size() > 0) {
                    for (Integer sgb = 0; sgb < groupList_B.size(); sgb++) {
                        currRGNum = groupList_B.get(sgb).get(0).group;
                        if (currRGNum != 0) {
                            for (Integer sga = 0; sga < groupList_A.size(); sga++) {
                                prevRGNum = groupList_A.get(sga).get(0).group;
                                if (prevRGNum != 0) {

                                    dist = groupList_B.get(sgb)
                                            .getDistanceToGroupInSameConcept(groupList_A.get(sga));
                                    List<Integer[]> tmplist;
                                    if (mapGroups.containsKey(currRGNum)) {
                                        tmplist = mapGroups.get(currRGNum);
                                    } else {
                                        tmplist = new ArrayList<Integer[]>();

                                    }
                                    tmplist.add(new Integer[] { prevRGNum, dist });
                                    mapGroups.put(currRGNum, tmplist);

                                    List<Integer[]> tmplist2;
                                    if (minDist.containsKey(prevRGNum)) {
                                        tmplist2 = minDist.get(prevRGNum);
                                    } else {
                                        tmplist2 = new ArrayList<Integer[]>();
                                    }
                                    tmplist2.add(new Integer[] { currRGNum, dist });
                                    minDist.put(prevRGNum, tmplist2);
                                }
                            }
                        }
                    }
                    HashMap<Integer, Integer> endMap = new HashMap<Integer, Integer>();

                    if (mapGroups.size() > 0) {
                        Integer bestPrevRGNum;
                        Integer bestCurrRGNum;
                        List<Integer> usageCurrGroups = new ArrayList<Integer>();
                        List<Integer> usagePrevGroups = new ArrayList<Integer>();
                        boolean incomplete = true;
                        boolean tooMuchPrev = false;
                        boolean tooMuchCurr = false;
                        while (incomplete && !tooMuchPrev && !tooMuchCurr) {
                            incomplete = false;
                            for (Integer sgb = 0; sgb < groupList_B.size(); sgb++) {
                                currRGNum = groupList_B.get(sgb).get(0).group;
                                if (!usageCurrGroups.contains(currRGNum)) {
                                    incomplete = true;
                                    List<Integer[]> currDistances = mapGroups.get(currRGNum);
                                    bestPrevRGNum = getBestGroupNumber(currDistances, usagePrevGroups);
                                    if (bestPrevRGNum == null) {
                                        tooMuchCurr = true;
                                        break;
                                    }
                                    List<Integer[]> prevDistances = minDist.get(bestPrevRGNum);
                                    bestCurrRGNum = getBestGroupNumber(prevDistances, usageCurrGroups);
                                    if (bestCurrRGNum == null) {
                                        tooMuchPrev = true;
                                        break;
                                    }
                                    if (bestCurrRGNum == currRGNum) {
                                        endMap.put(currRGNum, bestPrevRGNum);
                                        usageCurrGroups.add(currRGNum);
                                        usagePrevGroups.add(bestPrevRGNum);
                                    }
                                }
                            }
                        }
                    }
                    Integer nextNum;
                    for (Integer sgb = 0; sgb < groupList_B.size(); sgb++) {
                        currRGNum = groupList_B.get(sgb).get(0).group;
                        if (!endMap.containsKey(currRGNum)) {
                            nextNum = nextRoleGroupNumber(endMap);
                            endMap.put(currRGNum, nextNum);
                        }
                    }
                    for (RelationshipGroup relationshipGroup : groupList_B) {
                        for (Relationship relationship : relationshipGroup) {
                            if (relationship.group != endMap.get(relationship.group)) {
                                countChangedGroupNumber++;
                                relationship.group = endMap.get(relationship.group);
                            }
                        }
                    }
                }
            } else if (rel_A.sourceId > rel_B.sourceId) {
                // CASE 2: LIST_B HAS CONCEPT NOT IN LIST_A
                long thisC1 = rel_B.sourceId;
                while (rel_B.sourceId == thisC1) {

                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                        break;
                    }
                }

            } else {
                // CASE 3: LIST_A HAS CONCEPT NOT IN LIST_B
                long thisC1 = rel_A.sourceId;
                while (rel_A.sourceId == thisC1) {
                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                        break;
                    }
                }
            }
        }

        s.append("\r\n::: Relationships with group number changes = \t" + countChangedGroupNumber);
        s.append("\r\n::: [Partial time] Sort/Compare Input & Output: \t" + toStringLapseSec(startTime)
                + "\t(mS)\t");
        s.append("\r\n");
        logger.info(s.toString());
    }

    /**
     * Gets the best group number.
     *
     * @param distances the distances
     * @param usageGroups the usage groups
     * @return the best group number
     */
    private Integer getBestGroupNumber(List<Integer[]> distances, List<Integer> usageGroups) {
        Integer bestGr = null;
        Integer prevDist = Integer.MAX_VALUE;
        for (Integer[] tuple : distances) {
            if (!usageGroups.contains(tuple[0])) {
                Integer dist = tuple[1];
                if (dist <= prevDist) {
                    bestGr = tuple[0];
                    prevDist = dist;
                }
            }
        }
        return bestGr;
    }

    /**
     * Next role group number.
     *
     * @param map the map
     * @return the integer
     */
    private Integer nextRoleGroupNumber(HashMap<Integer, Integer> map) {

        Integer testNum = 1;
        boolean exists = true;
        while (exists) {
            exists = false;
            for (Integer i : map.keySet()) {
                if (map.get(i) == testNum) {
                    exists = true;
                    break;
                }
            }

            if (exists) {
                testNum++;
            }
        }

        return testNum;
    }

    /**
     * Compare prev inact.
     *
     * @param step the step
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private String comparePrevInact(int step) throws IOException {
        // STATISTICS COUNTERS
        int countSameISA = 0;
        int countA_Diff = 0;
        int countB_Diff = 0;
        int countB_DiffISA = 0;
        int countB_Total = 0;
        int sumPrevInact = 0;
        int sumNewNoRec = 0;
        long startTime = System.currentTimeMillis();

        StringBuilder s = new StringBuilder();
        s.append(
                "\r\n::: [Reconciliation by previous inactives vs current actives, without grouping comparation - step:"
                        + step + "]");

        boolean reconciled = false;
        for (Long conceptId : newNoRec.keySet()) {
            TreeMap<String, Relationship> relsPrev = prevInact.get(conceptId);
            ArrayList<Relationship> relsCurr = newNoRec.get(conceptId);
            sumNewNoRec += relsCurr.size();
            if (relsPrev != null) {
                sumPrevInact += relsPrev.size();
                for (Relationship relC : relsCurr) {
                    reconciled = false;
                    for (String key : relsPrev.descendingKeySet()) {
                        Relationship relP = relsPrev.get(key);
                        if (compareRelsStep(relC, relP, step)) {
                            writeReconciled(bw, relC, relP);

                            countB_Total++;
                            if (relC.typeId == isa) {
                                countSameISA++;
                            }
                            reconciled = true;
                            relsPrev.remove(key);
                            break;
                        }
                    }
                    if (!reconciled) {
                        countB_Diff++;
                        if (relC.typeId == isa) {
                            countB_DiffISA++;
                        }
                        writeNewNoRec(relC);
                    }
                }
                prevInact.put(conceptId, relsPrev);
            } else {
                for (Relationship relC : relsCurr) {
                    countB_Diff++;
                    if (relC.typeId == isa) {
                        countB_DiffISA++;
                    }
                    writeNewNoRec(relC);

                }
            }

        }

        s.append("\r\n::: Current active relationships to reconcile = \t" + sumNewNoRec);
        s.append("\r\n::: Candidate previous inactive relationships to match = \t" + sumPrevInact);

        s.append("\r\n::: Partial process statistics:");
        s.append("\r\n::: Reconciled relationships:  \t").append(countB_Total);
        s.append("\r\n::: Reconciled Isa's relationships:  \t").append(countSameISA);
        s.append("\r\n::: Previous relationships without match :   \t").append(countA_Diff);
        s.append("\r\n::: Current relationships without match:   \t").append(countB_Diff);
        s.append("\r\n::: Current Isa's relationships without match:\t").append(countB_DiffISA);
        s.append("\r\n::: ");

        long lapseTime = System.currentTimeMillis() - startTime;
        s.append("\r\n::: [Partial time] Sort/Compare Input & Output: \t").append(lapseTime);
        s.append("\t(mS)\t");
        s.append("\r\n");

        sumB_Total += countB_Total;
        sumSameISA += countSameISA;
        sumA_Diff = countA_Diff;
        sumB_Diff = countB_Diff;
        sumB_DiffISA = countB_DiffISA;

        return s.toString();
    }

    /**
     * Compare actives wo match.
     *
     * @param step the step
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private String compareActivesWOMatch(int step) throws IOException {
        // STATISTICS COUNTERS
        int countSameISA = 0;
        int countA_Diff = 0;
        int countB_Diff = 0;
        int countB_DiffISA = 0;
        int countB_Total = 0;
        int sumNewNoRec = 0;
        int sumPrevActNowRet = 0;
        long startTime = System.currentTimeMillis();

        StringBuilder s = new StringBuilder();
        s.append(
                "\r\n::: [Reconciliation by previous actives vs current actives, without grouping comparation - step:"
                        + step + "]");

        boolean reconciled = false;
        for (Long conceptId : newNoRec.keySet()) {

            ArrayList<Relationship> relsPrev = prevActNowRet.get(conceptId);
            ArrayList<Relationship> relsCurr = newNoRec.get(conceptId);

            sumNewNoRec += relsCurr.size();
            if (relsPrev != null) {
                sumPrevActNowRet += relsPrev.size();
                for (Relationship relC : relsCurr) {
                    reconciled = false;
                    for (Relationship relP : relsPrev) {
                        if (compareRelsStep(relC, relP, step)) {
                            writeReconciled(bw, relC, relP);
                            countB_Total++;
                            if (relC.typeId == isa) {
                                countSameISA++;
                            }
                            reconciled = true;
                            relsPrev.remove(relP);
                            break;
                        }
                    }
                    if (!reconciled) {
                        countB_Diff++;
                        if (relC.typeId == isa) {
                            countB_DiffISA++;
                        }
                        writeNewNoRec(relC);
                    }
                }

                countA_Diff += relsPrev.size();
                prevActNowRet.put(conceptId, relsPrev);
            } else {
                for (Relationship relC : relsCurr) {
                    countB_Diff++;
                    if (relC.typeId == isa) {
                        countB_DiffISA++;
                    }
                    writeNewNoRec(relC);
                }
            }

        }

        s.append("\r\n::: Current active relationships to reconcile = \t" + sumNewNoRec);
        s.append("\r\n::: Candidate previous active relationships to match = \t" + sumPrevActNowRet);

        s.append("\r\n::: Partial process statistics:");
        s.append("\r\n::: Reconciled relationships:  \t").append(countB_Total);
        s.append("\r\n::: Reconciled Isa's relationships:  \t").append(countSameISA);
        s.append("\r\n::: Previous relationships without match :   \t").append(countA_Diff);
        s.append("\r\n::: Current relationships without match:   \t").append(countB_Diff);
        s.append("\r\n::: Current Isa's relationships without match:\t").append(countB_DiffISA);
        s.append("\r\n::: ");

        long lapseTime = System.currentTimeMillis() - startTime;
        s.append("\r\n::: [Partial time] Sort/Compare Input & Output: \t").append(lapseTime);
        s.append("\t(mS)\t");
        s.append("\r\n");

        sumB_Total += countB_Total;
        sumSameISA += countSameISA;
        sumA_Diff = countA_Diff;
        sumB_Diff = countB_Diff;
        sumB_DiffISA = countB_DiffISA;

        return s.toString();
    }

    /**
     * Compare rels step.
     *
     * @param inR the in r
     * @param outR the out r
     * @param step the step
     * @return true, if successful
     */
    private boolean compareRelsStep(Relationship inR, Relationship outR, int step) {

        switch (step) {

        case 1:
            if ((inR.sourceId == outR.sourceId) && (inR.group == outR.group) && (inR.typeId == outR.typeId)
                    && (inR.destinationId == outR.destinationId) && (inR.effTime == outR.effTime)) {
                return true;
            }
            return false;
        case 2:
            if ((inR.sourceId == outR.sourceId) && (inR.typeId == outR.typeId)
                    && (inR.destinationId == outR.destinationId) && (inR.effTime == outR.effTime)) {
                return true;
            }
            return false;
        case 3:
            if ((inR.sourceId == outR.sourceId) && (inR.typeId == outR.typeId)
                    && (inR.destinationId == outR.destinationId) && (inR.group == outR.group)) {
                return true;
            }
            return false;
        case 4:
            if ((inR.sourceId == outR.sourceId) && (inR.typeId == outR.typeId)
                    && (inR.destinationId == outR.destinationId)) {
                return true;
            }
            return false;
        }
        return false;
    }

    /**
     * To string lapse sec.
     *
     * @param startTime the start time
     * @return the string
     */
    private String toStringLapseSec(long startTime) {
        StringBuilder s = new StringBuilder();
        long stopTime = System.currentTimeMillis();
        long lapseTime = stopTime - startTime;
        s.append((float) lapseTime / 1000).append(" (seconds)");
        return s.toString();
    }

    /**
     * Load active inferred relationship.
     *
     * @param relationshipFiles the relationship files
     * @param rels the rels
     * @param i the i
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void loadActiveInferredRelationship(String[] relationshipFiles, ArrayList<Relationship> rels, int i)
            throws IOException {

        String line;
        String[] spl;

        long c1;
        long c2;
        int rg;
        long ty;
        int et;
        long mo;
        short ac;
        long ch = Long.parseLong(I_Constants.INFERRED);

        for (String relFile : relationshipFiles) {
            FileInputStream rfis = new FileInputStream(relFile);
            InputStreamReader risr = new InputStreamReader(rfis, "UTF-8");
            BufferedReader rbr = new BufferedReader(risr);
            rbr.readLine();

            while ((line = rbr.readLine()) != null) {

                spl = line.split("\t", -1);
                if (spl[2].equals("1") && spl[8].equals(I_Constants.INFERRED)) {
                    c1 = Long.parseLong(spl[4]);
                    c2 = Long.parseLong(spl[5]);
                    rg = Integer.parseInt(spl[6]);
                    ty = Long.parseLong(spl[7]);
                    et = Integer.parseInt(spl[1]);
                    mo = Long.parseLong(spl[3]);
                    ac = Short.parseShort(spl[2]);
                    String rid;
                    if (i == 0) {
                        rid = "";
                    } else {
                        rid = spl[0];
                    }
                    Relationship rel = new Relationship(c1, c2, ty, rg, rid, et, mo, ac, ch);
                    rels.add(rel);
                }
            }
            rbr.close();
            rbr = null;
        }
    }

    /**
     * Load not active inferred relationship.
     *
     * @param relationshipFiles the relationship files
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void loadNotActiveInferredRelationship(String[] relationshipFiles) throws IOException {

        String line;
        String[] spl;

        long c1;
        long c2;
        int rg;
        long ty;
        int et;
        long mo;
        short ac;
        long ch;

        for (String relFile : relationshipFiles) {
            FileInputStream rfis = new FileInputStream(relFile);
            InputStreamReader risr = new InputStreamReader(rfis, "UTF-8");
            BufferedReader rbr = new BufferedReader(risr);
            rbr.readLine();

            TreeMap<String, Relationship> tRels;
            while ((line = rbr.readLine()) != null) {

                spl = line.split("\t", -1);
                if (!spl[2].equals("1") && spl[8].equals(I_Constants.INFERRED)) {

                    c1 = Long.parseLong(spl[4]);
                    c2 = Long.parseLong(spl[5]);
                    rg = Integer.parseInt(spl[6]);
                    ty = Long.parseLong(spl[7]);
                    et = Integer.parseInt(spl[1]);
                    mo = Long.parseLong(spl[3]);
                    ac = Short.parseShort(spl[2]);
                    ch = Long.parseLong(spl[8]);

                    Relationship rel = new Relationship(c1, c2, ty, rg, spl[0], et, mo, ac, ch);

                    if (prevInact.containsKey(c1)) {
                        tRels = prevInact.get(c1);
                    } else {
                        tRels = new TreeMap<String, Relationship>();
                    }
                    tRels.put(spl[1] + spl[0], rel);
                    prevInact.put(c1, tRels);
                }
            }
            rbr.close();
            rbr = null;
        }
    }

    /**
     * Write no reconciled rel.
     *
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private void writeNoReconciledRel() throws IOException {

        for (Long conceptId : newNoRec.keySet()) {
            List<Relationship> rels = newNoRec.get(conceptId);
            for (Relationship infRel : rels) {
                writeRF2TypeLine(bw, "null", infRel.effTime, 1, infRel.module, infRel.sourceId,
                        infRel.destinationId, infRel.group, infRel.typeId, I_Constants.INFERRED,
                        I_Constants.SOMEMODIFIER);
            }
        }

    }

    /**
     * Write reconciled.
     *
     * @param bw the bw
     * @param infRel the inf rel
     * @param prevRel the prev rel
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private void writeReconciled(BufferedWriter bw, Relationship infRel, Relationship prevRel) throws IOException {

        writeRF2TypeLine(bw, prevRel.getRelId(), infRel.effTime, 1, infRel.module, infRel.sourceId,
                infRel.destinationId, infRel.group, infRel.typeId, I_Constants.INFERRED, I_Constants.SOMEMODIFIER);

    }

    /**
     * Write r f2 type line.
     *
     * @param bw the bw
     * @param relationshipId the relationship id
     * @param effectiveTime the effective time
     * @param active the active
     * @param moduleId the module id
     * @param sourceId the source id
     * @param destinationId the destination id
     * @param relationshipGroup the relationship group
     * @param relTypeId the rel type id
     * @param characteristicTypeId the characteristic type id
     * @param modifierId the modifier id
     * @throws IOException Signals that an I/O exception has occurred.
     */

    public static void writeRF2TypeLine(BufferedWriter bw, String relationshipId, int effectiveTime, int active,
            long moduleId, long sourceId, long destinationId, int relationshipGroup, long relTypeId,
            String characteristicTypeId, String modifierId) throws IOException {
        bw.append(relationshipId + "\t" + effectiveTime + "\t" + active + "\t" + moduleId + "\t" + sourceId + "\t"
                + destinationId + "\t" + relationshipGroup + "\t" + relTypeId + "\t" + characteristicTypeId + "\t"
                + modifierId);
        bw.append("\r\n");
    }

    /**
     * Compare actives and write back.
     *
     * @param snorelA the snorel a
     * @param snorelB the snorel b
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private String compareActivesAndWriteBack(List<Relationship> snorelA, List<Relationship> snorelB)
            throws IOException {

        // STATISTICS COUNTERS
        int countA_Diff = 0;
        int countA_DiffISA = 0;
        int countB_Diff = 0;
        int countB_DiffISA = 0;
        int countB_Total = 0;
        int countSameISA = 0;

        long startTime = System.currentTimeMillis();
        Collections.sort(snorelA);
        Collections.sort(snorelB);

        Iterator<Relationship> itA = snorelA.iterator();
        Iterator<Relationship> itB = snorelB.iterator();
        Relationship rel_A = null;
        boolean done_A = false;
        if (itA.hasNext()) {
            rel_A = itA.next();
        } else {
            done_A = true;
        }
        Relationship rel_B = null;
        boolean done_B = false;
        if (itB.hasNext()) {
            rel_B = itB.next();
        } else {
            done_B = true;
        }

        StringBuilder s = new StringBuilder();
        s.append(
                "\r\n::: [Reconciliation by previous actives vs current actives, ungrouped and grouped comparation]"
                        + "\r\n::: Current active relationships to reconcile = \t" + snorelB.size()
                        + "\r\n::: Candidate Previous active relationships to match = \t" + snorelA.size());

        // BY SORT ORDER, LOWER NUMBER ADVANCES FIRST
        while (!done_A && !done_B) {

            if (rel_A.sourceId == rel_B.sourceId) {
                // COMPLETELY PROCESS ALL C1 FOR BOTH IN & OUT
                // PROCESS C1 WITH GROUP == 0
                long thisC1 = rel_A.sourceId;
                // PROCESS WHILE BOTH HAVE GROUP 0
                while (rel_A.sourceId == thisC1 && rel_B.sourceId == thisC1 && rel_A.group == 0 && rel_B.group == 0
                        && !done_A && !done_B) {

                    // PROGESS GROUP ZERO
                    switch (compareSnoRel(rel_A, rel_B)) {
                    case 1: // SAME
                        // GATHER STATISTICS
                        writeReconciled(bw, rel_B, rel_A);
                        countB_Total++;
                        if (rel_A.typeId == isa) {
                            countSameISA++;
                        }
                        if (itA.hasNext()) {
                            rel_A = itA.next();
                        } else {
                            done_A = true;
                        }
                        if (itB.hasNext()) {
                            rel_B = itB.next();
                        } else {
                            done_B = true;
                        }
                        break;

                    case 2: // REL_A > REL_B -- B has extra stuff
                        countB_Diff++;
                        if (rel_B.typeId == isa) {
                            countB_DiffISA++;
                        }
                        writeNewNoRec(rel_B);

                        if (itB.hasNext()) {
                            rel_B = itB.next();
                        } else {
                            done_B = true;
                        }
                        break;

                    case 3: // REL_A < REL_B -- A has extra stuff
                        // GATHER STATISTICS
                        countA_Diff++;
                        if (rel_A.typeId == isa) {
                            countA_DiffISA++;
                        }
                        writePrevActNowRet(rel_A);

                        if (itA.hasNext()) {
                            rel_A = itA.next();
                        } else {
                            done_A = true;
                        }
                        break;
                    } // switch
                }

                // REMAINDER LIST_A GROUP 0 FOR C1
                while (rel_A.sourceId == thisC1 && rel_A.group == 0 && !done_A) {

                    countA_Diff++;
                    if (rel_A.typeId == isa) {
                        countA_DiffISA++;
                    }
                    writePrevActNowRet(rel_A);
                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                        break;
                    }
                }

                // REMAINDER LIST_B GROUP 0 FOR C1
                while (rel_B.sourceId == thisC1 && rel_B.group == 0 && !done_B) {
                    countB_Diff++;
                    if (rel_B.typeId == isa) {
                        countB_DiffISA++;
                    }
                    writeNewNoRec(rel_B);
                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                        break;
                    }
                }

                // ** SEGMENT GROUPS **
                RelationshipGroupList groupList_A = new RelationshipGroupList();
                RelationshipGroupList groupList_B = new RelationshipGroupList();
                RelationshipGroup groupA = null;
                RelationshipGroup groupB = null;

                // SEGMENT GROUPS IN LIST_A
                int prevGroup = Integer.MIN_VALUE;
                while (rel_A.sourceId == thisC1 && !done_A) {
                    if (rel_A.group != prevGroup) {
                        groupA = new RelationshipGroup();
                        groupList_A.add(groupA);
                    }

                    groupA.add(rel_A);

                    prevGroup = rel_A.group;
                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                    }
                }
                // SEGMENT GROUPS IN LIST_B
                prevGroup = Integer.MIN_VALUE;
                while (rel_B.sourceId == thisC1 && !done_B) {
                    if (rel_B.group != prevGroup) {
                        groupB = new RelationshipGroup();
                        groupList_B.add(groupB);
                    }

                    groupB.add(rel_B);

                    prevGroup = rel_B.group;
                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                    }
                }

                // FIND GROUPS IN GROUPLIST_A WITHOUT AN EQUAL IN GROUPLIST_B
                RelationshipGroupList groupList_NotEqual;
                if (groupList_A.size() > 0) {
                    groupList_NotEqual = groupList_A.whichNotEqual(groupList_B);
                    for (RelationshipGroup sg : groupList_NotEqual) {
                        for (Relationship sr_A : sg) {

                            countA_Diff++;
                            writePrevActNowRet(sr_A);
                        }
                    }
                }

                // FIND GROUPS IN GROUPLIST_B WITHOUT AN EQUAL IN GROUPLIST_A
                if (groupList_B.size() > 0) {
                    groupList_NotEqual = groupList_B.whichNotEqual(groupList_A);
                    for (RelationshipGroup sg : groupList_NotEqual) {
                        if (sg.get(0).group != 0) {
                            for (Relationship sr_B : sg) {
                                countB_Diff++;
                                writeNewNoRec(sr_B);
                            }
                        } else {
                            for (Relationship sr_B : sg) {

                                countB_Diff++;
                                writeNewNoRec(sr_B);
                            }
                        }
                    }
                }
                if (groupList_A.size() > 0 && groupList_B.size() > 0) {
                    Map<Relationship, Relationship> relsMap;
                    relsMap = groupList_B.getEqualRelationshipInGroup(groupList_A);
                    for (Relationship sr_B : relsMap.keySet()) {
                        countB_Total++;
                        if (rel_B.typeId == isa) {
                            countSameISA++;
                        }
                        writeReconciled(bw, sr_B, relsMap.get(sr_B));

                    }
                }
            } else if (rel_A.sourceId > rel_B.sourceId) {
                // CASE 2: LIST_B HAS CONCEPT NOT IN LIST_A
                long thisC1 = rel_B.sourceId;
                while (rel_B.sourceId == thisC1) {
                    countB_Diff++;
                    if (rel_B.typeId == isa) {
                        countB_DiffISA++;
                    }
                    writeNewNoRec(rel_B);
                    if (itB.hasNext()) {
                        rel_B = itB.next();
                    } else {
                        done_B = true;
                        break;
                    }
                }

            } else {
                // CASE 3: LIST_A HAS CONCEPT NOT IN LIST_B
                long thisC1 = rel_A.sourceId;
                while (rel_A.sourceId == thisC1) {
                    countA_Diff++;
                    if (rel_A.typeId == isa) {
                        countA_DiffISA++;
                    }
                    writePrevActNowRet(rel_A);
                    if (itA.hasNext()) {
                        rel_A = itA.next();
                    } else {
                        done_A = true;
                        break;
                    }
                }
            }
        }

        // AT THIS POINT, THE PREVIOUS C1 HAS BE PROCESSED COMPLETELY
        // AND, EITHER REL_A OR REL_B HAS BEEN COMPLETELY PROCESSED
        // AND, ANY REMAINDER IS ONLY ON REL_LIST_A OR ONLY ON REL_LIST_B
        // AND, THAT REMAINDER HAS A "STANDALONE" C1 VALUE
        //
        // LASTLY, IF .NOT.DONE_A THEN THE NEXT REL_A IN ALREADY IN PLACE
        while (!done_A) {
            countA_Diff++;
            if (rel_A.typeId == isa) {
                countA_DiffISA++;
            }
            writePrevActNowRet(rel_A);
            if (itA.hasNext()) {
                rel_A = itA.next();
            } else {
                done_A = true;
                break;
            }
        }

        while (!done_B) {
            countB_Diff++;
            if (rel_B.typeId == isa) {
                countB_DiffISA++;
            }
            writeNewNoRec(rel_B);
            if (itB.hasNext()) {
                rel_B = itB.next();
            } else {
                done_B = true;
                break;
            }
        }

        s.append("\r\n::: Partial process statistics:");
        s.append("\r\n::: Reconciled relationships:  \t").append(countB_Total);
        s.append("\r\n::: Reconciled Isa's relationships:  \t").append(countSameISA);
        s.append("\r\n::: Previous relationships without match :   \t").append(countA_Diff);
        //      s.append("\r\n::: Previous Isa's relationships without match:\t").append(countA_DiffISA);
        s.append("\r\n::: Current relationships without match:   \t").append(countB_Diff);
        s.append("\r\n::: Current Isa's relationships without match:\t").append(countB_DiffISA);
        s.append("\r\n::: ");
        long lapseTime = System.currentTimeMillis() - startTime;
        s.append("\r\n::: [Partial time] Sort/Compare Input & Output: \t").append(lapseTime);
        s.append("\t(mS)\t");
        s.append("\r\n");

        sumB_Total += countB_Total;
        sumSameISA += countSameISA;
        sumA_Diff += countA_Diff;
        //      sumA_DiffISA+=countA_DiffISA;
        sumB_Diff += countB_Diff;
        sumB_DiffISA += countB_DiffISA;

        return s.toString();
    }

    /**
     * Write prev act now ret.
     *
     * @param rel_A the rel_ a
     */
    private void writePrevActNowRet(Relationship rel_A) {
        ArrayList<Relationship> rels;
        if (prevActNowRet.containsKey(rel_A.sourceId)) {
            rels = prevActNowRet.get(rel_A.sourceId);
        } else {
            rels = new ArrayList<Relationship>();
        }
        rels.add(rel_A);
        prevActNowRet.put(rel_A.sourceId, rels);
    }

    /**
     * Write new no rec.
     *
     * @param rel_B the rel_ b
     */
    private void writeNewNoRec(Relationship rel_B) {
        ArrayList<Relationship> rels;
        if (tmpNewNoRec.containsKey(rel_B.sourceId)) {
            rels = tmpNewNoRec.get(rel_B.sourceId);
        } else {
            rels = new ArrayList<Relationship>();
        }
        rels.add(rel_B);
        tmpNewNoRec.put(rel_B.sourceId, rels);

    }

    /**
     * Compare sno rel.
     *
     * @param inR the in r
     * @param outR the out r
     * @return the int
     */
    private static int compareSnoRel(Relationship inR, Relationship outR) {
        if ((inR.sourceId == outR.sourceId) && (inR.group == outR.group) && (inR.typeId == outR.typeId)
                && (inR.destinationId == outR.destinationId)) {
            return 1; // SAME
        } else if (inR.sourceId > outR.sourceId) {
            return 2; // ADDED
        } else if ((inR.sourceId == outR.sourceId) && (inR.group > outR.group)) {
            return 2; // ADDED
        } else if ((inR.sourceId == outR.sourceId) && (inR.group == outR.group) && (inR.typeId > outR.typeId)) {
            return 2; // ADDED
        } else if ((inR.sourceId == outR.sourceId) && (inR.group == outR.group) && (inR.typeId == outR.typeId)
                && (inR.destinationId > outR.destinationId)) {
            return 2; // ADDED
        } else {
            return 3; // DROPPED
        }
    } // compareSnoRel

    /**
     * Gets the params.
     *
     * @return the params
     * @throws ConfigurationException the configuration exception
     */
    @SuppressWarnings("unchecked")
    private void getParams() throws ConfigurationException {

        try {
            xmlConfig = new XMLConfiguration(config);
        } catch (ConfigurationException e) {
            logger.info("Reconciliation Runner - Error happened getting params file." + e.getMessage());
            throw e;
        }

        List<String> relFiles = xmlConfig.getList(I_Constants.CURRENT_INFERRED_RELATIONSHIP_FILES);
        currentRelationshipsFile = new String[relFiles.size()];
        relFiles.toArray(currentRelationshipsFile);

        List<String> prevRelFiles = xmlConfig.getList(I_Constants.PREVIOUS_INFERRED_RELATIONSHIP_FILES);
        if (prevRelFiles != null && prevRelFiles.size() > 0) {
            previousInferredRelationshipsFile = new String[prevRelFiles.size()];
            prevRelFiles.toArray(previousInferredRelationshipsFile);
        }
        outputRelationships = xmlConfig.getString(I_Constants.RELATIONSHIP_FILE);
        logger.info("Reconciliation - Parameters:");
        logger.info("Current Relationship files : ");
        if (currentRelationshipsFile != null) {
            for (String relFile : currentRelationshipsFile) {
                logger.info(relFile);
            }
        }
        logger.info("Previous Relationship files : ");
        if (previousInferredRelationshipsFile != null) {
            for (String relFile : previousInferredRelationshipsFile) {
                logger.info(relFile);
            }
        }
        logger.info("Output Relationship file : " + outputRelationships);
    }
}