/*******************************************************************************
 * Copyright 2014 Centre for Development of Advanced Computing(C-DAC), Pune
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package in.cdac.medinfo.csnotk.csnolib.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import in.cdac.medinfo.csnotk.csnolib.commons.Constants;
import in.cdac.medinfo.csnotk.csnolib.commons.DBSchemaMapping;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumCaseSignificance;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumCharacteristicType;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumComponent;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumDescType;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumModifier;
import in.cdac.medinfo.csnotk.csnolib.commons.EnumSemanticTag;
import in.cdac.medinfo.csnotk.csnolib.db.ConnectionManager;
import in.cdac.medinfo.csnotk.csnolib.db.DBUtil;
import in.cdac.medinfo.csnotk.csnolib.exception.ConceptDefException;
import in.cdac.medinfo.csnotk.csnolib.exception.ConceptFSNException;
import in.cdac.medinfo.csnotk.csnolib.exception.ConceptStateException;
import in.cdac.medinfo.csnotk.csnolib.model.ComponentFactory;
import in.cdac.medinfo.csnotk.csnolib.model.CompositeDescription;
import in.cdac.medinfo.csnotk.csnolib.model.Concept;
import in.cdac.medinfo.csnotk.csnolib.model.ConcreteRelationship;
import in.cdac.medinfo.csnotk.csnolib.model.RefSetMember;
import in.cdac.medinfo.csnotk.csnolib.model.Refset;
import in.cdac.medinfo.csnotk.csnolib.model.Relationship;
import in.cdac.medinfo.csnotk.csnolib.model.RelationshipTC;
import in.cdac.medinfo.csnotk.csnolib.model.SimpleMapRefset;
//Logs
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

/**
 * Provides utility of concept, description and refset.
 *
 */
public class SnoDomainUtil {
	Connection connection;
	Statement statement;
	ResultSet resultSet;
	private List<CompositeDescription> compositeDescriptionList = null;
	private List<RelationshipTC> relationship_tcList = null;
	private static final String[] definitionColumnArray = { DBSchemaMapping.TEXTDEFINITION_ID,
			DBSchemaMapping.TEXTDEFINITION_ACTIVE, DBSchemaMapping.TEXTDEFINITION_CONCEPTID,
			DBSchemaMapping.TEXTDEFINITION_TYPE_ID, DBSchemaMapping.TEXTDEFINITION_TERM,
			DBSchemaMapping.TEXTDEFINITION_MODULEID, DBSchemaMapping.TEXTDEFINITION_EFFECTIVE_TIME,
			DBSchemaMapping.TEXTDEFINITION_CASE_SIGNIFICANCE_ID, DBSchemaMapping.TEXTDEFINITION_LANGUAGE_CODE };
	private static final String[] columnArray = { DBSchemaMapping.DESCRIPTION_ID, DBSchemaMapping.DESCRIPTION_ACTIVE,
			DBSchemaMapping.DESCRIPTION_CONCEPT_ID, DBSchemaMapping.DESCRIPTION_TYPE_ID,
			DBSchemaMapping.DESCRIPTION_TERM, DBSchemaMapping.DESCRIPTION_MODULE_ID,
			DBSchemaMapping.DESCRIPTION_EFFECTIVE_TIME, DBSchemaMapping.DESCRIPTION_CASE_SIGNIFICANCE_ID,
			DBSchemaMapping.DESCRIPTION_LANGUAGE_CODE };
	private static final String[] relationshipColumnArray = { DBSchemaMapping.RELATIONSHIP_ID,
			DBSchemaMapping.RELATIONSHIP_EFFECTIVE_TIME, DBSchemaMapping.RELATIONSHIP_ACTIVE,
			DBSchemaMapping.RELATIONSHIP_MODULE_ID, DBSchemaMapping.RELATIONSHIP_SOURCE_ID,
			DBSchemaMapping.RELATIONSHIP_DESTINATION_ID, DBSchemaMapping.RELATIONSHIP_RELATIONSHIP_GROUP,
			DBSchemaMapping.RELATIONSHIP_TYPEID, DBSchemaMapping.RELATIONSHIP_CHARACTERISTIC_TYPE_ID,
			DBSchemaMapping.RELATIONSHIP_MODIFIER_ID };
	private static final String[] refsetLangColoumnArray = { DBSchemaMapping.REFSETLANG_REFERENCED_COMPONENT_ID,
			DBSchemaMapping.REFSETLANG_REFSET_ID, DBSchemaMapping.REFSETLANG_ACTIVE,
			DBSchemaMapping.REFSETLANG_ACCEPTABILITY_ID };
	private static final String[] relationshipTCColumnArray = { "parentId", "childId", "countOfChildrens",
			"isImmediateChildren" };
	private static final String[] simpleMapColumnArray = { DBSchemaMapping.SIMPLEMAP_ID,
			DBSchemaMapping.SIMPLEMAP_EFFECTIVE_TIME, DBSchemaMapping.SIMPLEMAP_ACTIVE,
			DBSchemaMapping.SIMPLEMAP_MODULE_ID, DBSchemaMapping.SIMPLEMAP_REFSET_ID,
			DBSchemaMapping.SIMPLEMAP_REFERENCED_COMPONENT_ID, DBSchemaMapping.SIMPLEMAP_MAP_TARGET };
	private static final String[] concreteRelationshipColumnArray = { DBSchemaMapping.CONCRETE_RELATIONSHIP_ID,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_EFFECTIVE_TIME, DBSchemaMapping.CONCRETE_RELATIONSHIP_ACTIVE,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_MODULE_ID, DBSchemaMapping.CONCRETE_RELATIONSHIP_SOURCE_ID,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_DESTINATIONVALUE,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_RELATIONSHIP_GROUP, DBSchemaMapping.CONCRETE_RELATIONSHIP_TYPEID,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_CHARACTERISTIC_TYPE_ID,
			DBSchemaMapping.CONCRETE_RELATIONSHIP_MODIFIER_ID };
	private static SimpleDateFormat dateFormater = new SimpleDateFormat("yyyyMMdd");
	private static ComponentFactory componentFactory = ComponentFactory.getInstance();

	private long offset;
	private long numberOfRecords;
	Properties properties = null;
	private boolean flag = true;
    //Log
    private static final Logger logger = LogManager.getLogger(SnoDomainUtil.class);

	/**
	 * Returns list of {@link CompositeDescription}, {@link Relationship},
	 * {@link RelationshipTC}.
	 *
	 * @param <T>
	 * @param tableName    {@link String} name of the table
	 * @param offset       {@link Long} position of record
	 * @param totalRecords {@link Long} number of all record
	 * @return list of {@link CompositeDescription}, {@link Relationship},
	 *         {@link RelationshipTC}.
	 * @throws SQLException
	 * @throws ParseException
	 * @throws ConceptDefException
	 * @throws ConceptFSNException
	 * @throws ConceptStateException
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getDomain(String tableName, long offset, long totalRecords, boolean isExtensionSelected)
			throws SQLException, ParseException, ConceptStateException, ConceptFSNException, ConceptDefException {
		try {
			properties = PropertyReader.loadSystemProperties();
			connection = ConnectionManager.getConnection();
			statement = DBUtil.getStatement(connection);
			String schemaName = "";

			if (tableName != null && DBSchemaMapping.DESCRIPTION.equals(tableName)
					|| DBSchemaMapping.TEXTDEFINITION.equals(tableName)) {
				String[] descriptionRefsetLangColumnArray = new String[(int) (columnArray.length
						+ refsetLangColoumnArray.length)];
				int descriptionRefsetLangIndex = 0;

				if (tableName.equalsIgnoreCase(DBSchemaMapping.TEXTDEFINITION)) {
					schemaName = DBSchemaMapping.TEXTDEFINITION;
					tableName = DBSchemaMapping.TEXTDEFINITION + "," + DBSchemaMapping.REFSETLANG + " where "
							+ DBSchemaMapping.TEXTDEFINITION_ID + "="
							+ DBSchemaMapping.REFSETLANG_REFERENCED_COMPONENT_ID;
					for (String columnName : definitionColumnArray) {
						descriptionRefsetLangColumnArray[descriptionRefsetLangIndex] = columnName;
						descriptionRefsetLangIndex++;
					}
				} else {
					schemaName = DBSchemaMapping.DESCRIPTION;
					tableName = DBSchemaMapping.DESCRIPTION + "," + DBSchemaMapping.REFSETLANG + " where "
							+ DBSchemaMapping.DESCRIPTION_ID + "=" + DBSchemaMapping.REFSETLANG_REFERENCED_COMPONENT_ID;
					for (String columnName : columnArray) {
						descriptionRefsetLangColumnArray[descriptionRefsetLangIndex] = columnName;
						descriptionRefsetLangIndex++;
					}
				}
				for (String columnName : refsetLangColoumnArray) {
					descriptionRefsetLangColumnArray[descriptionRefsetLangIndex] = columnName;
					descriptionRefsetLangIndex++;
				}
				// SELECT count(*) FROM SCT2_DESCRIPTION, DER2_REFSET_LANG where
				// SCT2_DESCRIPTION.ID =DER2_REFSET_LANG.REFERENCEDCOMPONENTID
				tableName = modifyDBQuery(tableName, schemaName, isExtensionSelected);
				resultSet = DBUtil.retrieveColumns(tableName, descriptionRefsetLangColumnArray, statement, getOffset(),
						totalRecords, isExtensionSelected);
				compositeDescriptionList = new ArrayList<CompositeDescription>();
				if (tableName != null) {
					setDescriptionList(resultSet);
					setDescriptionListForQuickSearch();
				}
				if (schemaName.equalsIgnoreCase(DBSchemaMapping.TEXTDEFINITION)) {
					DBSchemaMapping.DESCRIPTION_TEXTDEFINITION_CURRENTID = "0"; // reset the common offset
				}

				int count = 1;
				if (count == 1) {
					compositeDescriptionList.get(0);
					count++;
				}
				return (List<T>) compositeDescriptionList;
			} else if (tableName != null && DBSchemaMapping.RELATIONSHIP.equals(tableName)) {
				schemaName = DBSchemaMapping.RELATIONSHIP;
				tableName = modifyDBQuery(tableName, schemaName, isExtensionSelected);
				resultSet = DBUtil.retrieveColumns(tableName, relationshipColumnArray, statement, getOffset(),
						totalRecords, isExtensionSelected);
				return (List<T>) setRelationshipList(resultSet);
			} else if (tableName != null && DBSchemaMapping.SIMPLEMAP.equals(tableName)) {
				schemaName = DBSchemaMapping.SIMPLEMAP;
				tableName = modifyDBQuery(tableName, schemaName, isExtensionSelected);
				resultSet = DBUtil.retrieveColumns(tableName, simpleMapColumnArray, statement, getOffset(),
						totalRecords, isExtensionSelected);
				return (List<T>) setSimpleMapList(resultSet);
			} else if (tableName != null && DBSchemaMapping.TRANSCLOSURE.equals(tableName)) {
				schemaName = DBSchemaMapping.TRANSCLOSURE;
				tableName = modifyDBQuery(tableName, schemaName, isExtensionSelected);
				resultSet = DBUtil.retrieveColumns(tableName, relationshipTCColumnArray, statement, getOffset(),
						totalRecords, isExtensionSelected);
				relationship_tcList = new ArrayList<RelationshipTC>();
				setRelationships_tcList(resultSet);
				return (List<T>) relationship_tcList;
			} else if (tableName != null && DBSchemaMapping.CONCRETE_RELATIONSHIP.equals(tableName)) {
				schemaName = DBSchemaMapping.CONCRETE_RELATIONSHIP;
				tableName = modifyDBQuery(tableName, schemaName, isExtensionSelected);
				resultSet = DBUtil.retrieveColumns(tableName, concreteRelationshipColumnArray, statement, getOffset(),
						totalRecords, isExtensionSelected);
				return (List<T>) setConcreteRelationshipList(resultSet);
			}
		} finally {
			DBUtil.closeResultSet(resultSet);
			DBUtil.closeStatement(statement);
		}
		return null;
	}

	/**
	 *
	 * The method modify the DB Query To Be Executed for international Edition
	 *
	 * @param tableName
	 * @param schemaName
	 * @param isExtensionSelected
	 * @return String DBQueryToBeExecuted
	 **/
	private String modifyDBQuery(String query, String schemaName, boolean isExtensionSelected) {
		if (isExtensionSelected) { // If Extension is selected do not modify the DBQuery
			return query;
		}
		switch (schemaName) {
		case DBSchemaMapping.TEXTDEFINITION: {
			return query + " AND " + DBSchemaMapping.TEXTDEFINITION_ID + ">="
					+ DBSchemaMapping.DESCRIPTION_TEXTDEFINITION_CURRENTID + " ORDER BY "
					+ DBSchemaMapping.TEXTDEFINITION_ID;
		}
		case DBSchemaMapping.DESCRIPTION: {
			return query + " AND " + DBSchemaMapping.DESCRIPTION_ID + ">="
					+ DBSchemaMapping.DESCRIPTION_TEXTDEFINITION_CURRENTID + " ORDER BY "
					+ DBSchemaMapping.DESCRIPTION_ID;
		}
		case DBSchemaMapping.RELATIONSHIP: {
			return query + " where " + DBSchemaMapping.RELATIONSHIP_ID + ">="
					+ DBSchemaMapping.RELATIONSHIP_CURRENTID + " ORDER BY " + DBSchemaMapping.RELATIONSHIP_ID;
		}
		case DBSchemaMapping.CONCRETE_RELATIONSHIP: {
			return query + " where " + DBSchemaMapping.CONCRETE_RELATIONSHIP_ID + ">="
					+ DBSchemaMapping.CONCRETE_RELATIONSHIP_CURRENTID + " ORDER BY "
					+ DBSchemaMapping.CONCRETE_RELATIONSHIP_ID;
		}
		case DBSchemaMapping.TRANSCLOSURE: {
			return query + " where " + DBSchemaMapping.TRANSCLOSURE + ".childid" + ">="
					+ DBSchemaMapping.TRANSCLOSURE_CURRENTID + " ORDER BY " + DBSchemaMapping.TRANSCLOSURE + ".childid";
		}
		default:
			logger.error(LoggerUtility.Exception, "query not modifiable for schema {}" , schemaName);
			break;
		}
		return query;
	}

	/**
	 * Returns list of {@link CompositeDescription}s.
	 *
	 * @param tableName    {@link String} name of the table
	 * @param offset       {@link Long} position of record
	 * @param totalRecords {@link Long} number of all record
	 * @return list of {@link CompositeDescription}s.
	 * @throws SQLException
	 * @throws ParseException
	 */

	/**
	 * Sets the values for the list of {@link RelationshipTC}s.
	 *
	 * @throws SQLException
	 */
	private void setRelationships_tcList(ResultSet resultSet) throws SQLException {
		RelationshipTC relationship_tc = null;
		while (resultSet.next()) {
			relationship_tc = new RelationshipTC();
			relationship_tc.setParentId(resultSet.getString(1));
			// getting child id data
			Concept concept = null;
			concept = (Concept) componentFactory.getComponent(EnumComponent.CONCEPT, resultSet.getString(2));
			relationship_tc.setChildConcept(concept);
			relationship_tc.setCountOfChildrens(Integer.parseInt(resultSet.getString(3)));
			relationship_tc.setIsImmediateChildren(resultSet.getShort(4));
			relationship_tcList.add(relationship_tc);
		}
		try {
			DBSchemaMapping.TRANSCLOSURE_CURRENTID = relationship_tcList.get(relationship_tcList.size() - 1)
					.getChildConcept().getId();
		} catch (ArrayIndexOutOfBoundsException exp) {
			logger.error(LoggerUtility.Exception, "Exception occurred in setRelationships_tcList Array index not found");
		}
	}

	/**
	 * Sets the values for the list of {@link CompositeDescription}s.
	 *
	 * @throws SQLException
	 * @throws ParseException
	 */
	private void setDescriptionList(ResultSet resultSet) throws SQLException, ParseException {
		CompositeDescription compositeDescription = null;
		RefSetMember refSetLangMember = null;
		while (resultSet.next()) {
			compositeDescription = new CompositeDescription();
			compositeDescription.setId(resultSet.getString(1));
			compositeDescription.setActiveStatus(resultSet.getByte(2));
			compositeDescription.setConceptId(resultSet.getString(3));
			compositeDescription.setType(EnumDescType.getEnum(resultSet.getString(4)));
			compositeDescription.setTerm(resultSet.getString(5));
			compositeDescription.setModuleId(resultSet.getString(6));
			compositeDescription.setTime(dateFormater.parse((resultSet.getString(7))));
			compositeDescription.setCaseSId(EnumCaseSignificance.getEnum(resultSet.getString(8)));
			compositeDescription.setLangCode(resultSet.getString(9));
			refSetLangMember = new RefSetMember();
			refSetLangMember.setReferencedComponentId(resultSet.getString(10));
			refSetLangMember.setRefSetId(resultSet.getString(11));
			refSetLangMember.setActiveStatus(resultSet.getByte(12));
			refSetLangMember.setAcceptabilityId(resultSet.getString(13));
			compositeDescription.setRefSetLangMember(refSetLangMember);
			compositeDescriptionList.add(compositeDescription);
		}

		try {
			DBSchemaMapping.DESCRIPTION_TEXTDEFINITION_CURRENTID = compositeDescriptionList
					.get(compositeDescriptionList.size() - 1).getId();
		} catch (ArrayIndexOutOfBoundsException exp) {
			logger.error(LoggerUtility.Exception, "Exception occurred in setDescriptionList Array index not found");
		}
	}

	/**
	 * Sets the values for the list of {@link CompositeDescription}s.
	 *
	 * @throws SQLException
	 * @throws ConceptStateMissing
	 */
	private void setDescriptionListForQuickSearch()
			throws SQLException, ConceptStateException, ConceptFSNException, ConceptDefException {
		String strSemanticTag = null;
		String conceptId = null;
		for (CompositeDescription compositeDescription : compositeDescriptionList) {
			conceptId = compositeDescription.getConceptId();

			compositeDescription.setIsPreferredTerm(isPreferredTerm(compositeDescription.getId()));
			compositeDescription.setConceptState(getConceptState(conceptId));
			compositeDescription.setConceptFsn(getConceptFsn(conceptId, compositeDescription.getLangCode()));
			compositeDescription.setDefinitionStatus(getConceptDefStatus(conceptId));
			//Semantic Tag determination based on Concept State
			if(compositeDescription.getConceptState().equalsIgnoreCase("1")) {
				strSemanticTag = getHierarchyByConceptID(compositeDescription.getConceptId(),
					compositeDescription.getType(), compositeDescription.getTerm(),
					compositeDescription.getActiveStatus(), compositeDescription.getLangCode());
				compositeDescription.setHierarchy(strSemanticTag);
			} else {
				compositeDescription.setHierarchy("inactive");
			}

		}
	}

	private List<Relationship> setRelationshipList(ResultSet result) throws SQLException, ParseException {
		List<Relationship> relationships = new ArrayList<Relationship>();
		if (null != result) {
			Relationship relationship = null;
			while (result.next()) {
				relationship = (Relationship) componentFactory.getComponent(EnumComponent.RELATIONSHIP, null);
				relationship.setId(result.getString(1));
				relationship.setTime(dateFormater.parse(result.getString(2)));
				relationship.setActiveStatus(result.getByte(3));
				relationship.setModuleId(result.getString(4));
				relationship.setSourceConcept(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(5).trim()));
				relationship.setDestinationConcept(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(6).trim()));
				relationship.setRelationshipGroup(result.getInt(7));
				relationship.setType(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(8).trim()));
				relationship.setCharacteristicTypeId(EnumCharacteristicType.getEnum(result.getString(9)));
				relationship.setModifierId(EnumModifier.getEnum(result.getString(10)));
				relationships.add(relationship);
			}
			try {
				DBSchemaMapping.RELATIONSHIP_CURRENTID = relationships.get(relationships.size() - 1).getId();
			} catch (ArrayIndexOutOfBoundsException exp) {
				logger.error(LoggerUtility.Exception, "Exception occurred in setRelationshipList Array index not found");
			}
		}
		return relationships;
	}

	private List<ConcreteRelationship> setConcreteRelationshipList(ResultSet result)
			throws SQLException, ParseException {
		List<ConcreteRelationship> relationships = new ArrayList<ConcreteRelationship>();
		if (null != result) {
			ConcreteRelationship relationship = null;
			while (result.next()) {
				relationship = (ConcreteRelationship) componentFactory.getComponent(EnumComponent.CONCRETERELATIONSHIP,
						null);
				relationship.setId(result.getString(1));
				relationship.setTime(dateFormater.parse(result.getString(2)));
				relationship.setActiveStatus(result.getByte(3));
				relationship.setModuleId(result.getString(4));
				relationship.setSourceConcept(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(5).trim()));
				String value = result.getString(6).replaceAll("[^a-zA-Z0-9\\.]", "");
				relationship.setDestinationValue(value);
				relationship.setDestinationValueWithPrefix(result.getString(6));
				relationship.setRelationshipGroup(result.getInt(7));
				relationship.setType(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(8).trim()));
				relationship.setCharacteristicTypeId(EnumCharacteristicType.getEnum(result.getString(9)));
				relationship.setModifierId(EnumModifier.getEnum(result.getString(10)));
				relationships.add(relationship);
			}
			try {
				DBSchemaMapping.CONCRETE_RELATIONSHIP_CURRENTID = relationships.get(relationships.size() - 1).getId();
			} catch (ArrayIndexOutOfBoundsException exp) {
				logger.error(LoggerUtility.Exception, "Exception occurred in setConcreteRelationshipList Array index not found");
			}
		}
		return relationships;
	}

	private List<SimpleMapRefset> setSimpleMapList(ResultSet result) throws SQLException, ParseException {
		List<SimpleMapRefset> simpleMapRefsets = new ArrayList<SimpleMapRefset>();
		if (null != result) {
			SimpleMapRefset simpleMapRefset = null;
			while (result.next()) {
				simpleMapRefset = (SimpleMapRefset) componentFactory.getComponent(EnumComponent.SIMPLEMAP, null);
				simpleMapRefset.setId(result.getString(1));
				simpleMapRefset.setTime(dateFormater.parse(result.getString(2)));
				simpleMapRefset.setActiveStatus(result.getByte(3));
				simpleMapRefset.setModuleId(result.getString(4));
				simpleMapRefset.setRefSetId(result.getString(5));
				simpleMapRefset.setreferencedComponent(
						(Concept) componentFactory.getComponent(EnumComponent.CONCEPT, result.getString(6).trim()));
				simpleMapRefset.setMapTarget(result.getString(7));
				simpleMapRefsets.add(simpleMapRefset);
			}
		}
		return simpleMapRefsets;
	}

	/**
	 * Retrieves the semantic tag/hierarchy of a particular concept.
	 *
	 * @param conceptId Concept identifier.
	 * @param typeId    It specifies the description type.
	 * @param term      The term that specifies the Description.
	 * @return {@link String} value that denotes the hierarchy to which the specific
	 *         term belongs.
	 * @throws SQLException
	 */
	public String getHierarchyByConceptID(String conceptId, String typeId, String term, int active, String languageCode)
			throws SQLException {
		String strSemanticTag = "";
		String strTypeID = "";
		if (typeId.equalsIgnoreCase(EnumDescType.FULLY_SPECIFIED_NAME.getValue()) && term.contains("(")
				&& term.contains(")") && active == 1) {
			String strST = SemanticTagBuilder.buildSemanticTagFromString(term);
			if (null == strST) {
				strSemanticTag = EnumSemanticTag.SITUATION_WITH_EXPLICIT_CONTEXT.getValue();
			} else
				strSemanticTag = strST;
		} else {
			resultSet = DBUtil.retrieveFSNforHierachy(conceptId, statement, languageCode);
			while (resultSet.next()) {
				term = resultSet.getString(1);
				strTypeID = resultSet.getString(2);
				if (strTypeID.equalsIgnoreCase(EnumDescType.FULLY_SPECIFIED_NAME.getValue()) && term.contains("(")
						&& term.contains(")")) {
					String strST = SemanticTagBuilder.buildSemanticTagFromString(term);
					if (null == strST) {
						strSemanticTag = EnumSemanticTag.SITUATION_WITH_EXPLICIT_CONTEXT.getValue();
						break;
					} else {
						strSemanticTag = strST;
					}
				}
			}

		}
		return strSemanticTag;
	}

	/**
	 * Retrieves Acceptability id of description which indicates preferred term for
	 * that description.
	 *
	 * @param descriptionId {@link String} value that refers to the description id.
	 * @return acceptability id which is a {@link String} value that corresponds to
	 *         the acceptability id.
	 * @throws SQLException
	 */
	private String isPreferredTerm(String descriptionId) throws SQLException {

		resultSet = DBUtil.retrieveAcceptabilityId(descriptionId, statement);

		if (!resultSet.next()) {
			return "0";
		} else {
			return "1";
		}

	}

	/**
	 * Returns the concept FSN.
	 *
	 * @param conceptId Concept identifier.
	 * @return {@link String} that refers to the FSN of that concept.
	 * @throws SQLException
	 */
	private String getConceptFsn(String conceptId, String languageCode) throws SQLException, ConceptFSNException {
		resultSet = DBUtil.retrieveConceptDetails(conceptId, languageCode, statement);
		if (resultSet.next())
			return resultSet.getString(1);
		else
			throw new ConceptFSNException(
					"Concept FSN is missing for concept id: " + conceptId + ", please check into Description file");
	}

	/**
	 * Returns the concept definition status.
	 *
	 * @param conceptId Concept identifier.
	 * @return {@link String} that represents the definition status of that concept.
	 * @throws SQLException
	 */
	private String getConceptDefStatus(String conceptId) throws SQLException, ConceptDefException {
		resultSet = DBUtil.retrieveConceptDetails(conceptId, statement);

		if (resultSet.next())
			return resultSet.getString(3);
		else
			throw new ConceptDefException(
					"Concept definition is missing for concept id: " + conceptId + ", please check into Concept file");

	}

	/**
	 * Gets State of specified Concept Id.
	 *
	 * @param conceptId Concept identifier.
	 * @return the concept state.
	 * @throws SQLException
	 * @throws ConceptStateMissing
	 */
	private String getConceptState(String conceptId) throws SQLException, ConceptStateException {
		resultSet = DBUtil.retrieveConceptState(conceptId, statement);

		if (resultSet.next())
			return resultSet.getString(1);
		else
			throw new ConceptStateException(
					"Concept state is missing for concept id: " + conceptId + ", please check into Concept file");

	}

	/**
	 * Gets the offset.
	 */
	public long getOffset() {
		return offset;
	}

	/**
	 * Sets the offset.
	 *
	 * @param offset offset value.
	 */
	public void setOffset(long offset) {
		this.offset = offset;
	}

	/**
	 * Gets the number of records / returnLimit.
	 */
	public long getNumberOfRecords() {
		return numberOfRecords;
	}

	/**
	 * Sets the number of records.
	 */
	public void setNumberOfRecords(long numberOfRecords) {
		this.numberOfRecords = numberOfRecords;
	}

	/**
	 * Sets the values for the list of {@link CompositeDescription}s.
	 *
	 * @throws SQLException
	 * @throws ParseException
	 */
	private void setRefsetList(ResultSet resultSet) throws SQLException, ParseException {
		CompositeDescription compositeDescription = null;
		RefSetMember refSetLangMember = null;
		Refset refset = null;
		while (resultSet.next()) {
			compositeDescription = new CompositeDescription();
			compositeDescription.setId(resultSet.getString(1));
			compositeDescription.setActiveStatus(resultSet.getByte(2));
			compositeDescription.setConceptId(resultSet.getString(3));
			compositeDescription.setType(EnumDescType.getEnum(resultSet.getString(4)));
			compositeDescription.setTerm(resultSet.getString(5));
			compositeDescription.setModuleId(resultSet.getString(6));
			compositeDescription.setTime(dateFormater.parse((resultSet.getString(7))));
			compositeDescription.setCaseSId(EnumCaseSignificance.getEnum(resultSet.getString(8)));
			compositeDescription.setLangCode(resultSet.getString(9));
			refSetLangMember = new RefSetMember();
			refSetLangMember.setReferencedComponentId(resultSet.getString(10));
			refSetLangMember.setRefSetId(resultSet.getString(11));
			refSetLangMember.setActiveStatus(resultSet.getByte(12));
			refSetLangMember.setAcceptabilityId(resultSet.getString(13));
			compositeDescription.setRefSetLangMember(refSetLangMember);

			refset = new Refset();
			refset.setRefSetId(resultSet.getString(14));
			refset.setModuleId(resultSet.getString(15));
			refset.setResetActive(Integer.parseInt(resultSet.getString(16)));
			compositeDescription.setRefset(refset);
			compositeDescriptionList.add(compositeDescription);
		}
	}

	/**
	 * Sets the values for the list of {@link CompositeDescription}s.
	 *
	 * @throws SQLException
	 * @throws ParseException
	 */
	private void setcRefsetList(ResultSet resultSet, boolean flag) throws SQLException, ParseException {
		CompositeDescription compositeDescription = null;
		RefSetMember refSetLangMember = null;
		Refset refset = null;
		while (resultSet.next()) {
			compositeDescription = new CompositeDescription();
			compositeDescription.setId(resultSet.getString(1));
			compositeDescription.setActiveStatus(resultSet.getByte(2));
			compositeDescription.setConceptId(resultSet.getString(3));
			compositeDescription.setType(EnumDescType.getEnum(resultSet.getString(4)));
			compositeDescription.setTerm(resultSet.getString(5));
			compositeDescription.setModuleId(resultSet.getString(6));
			compositeDescription.setTime(dateFormater.parse((resultSet.getString(7))));
			compositeDescription.setCaseSId(EnumCaseSignificance.getEnum(resultSet.getString(8)));
			compositeDescription.setLangCode(resultSet.getString(9));
			if (!flag) {
				refSetLangMember = new RefSetMember();
				refSetLangMember.setReferencedComponentId(resultSet.getString(10));
				refSetLangMember.setRefSetId(resultSet.getString(11));
				refSetLangMember.setActiveStatus(resultSet.getByte(12));
				refSetLangMember.setAcceptabilityId(resultSet.getString(13));
				compositeDescription.setRefSetLangMember(refSetLangMember);
				refset = new Refset();
				refset.setRefSetId(resultSet.getString(14));
				refset.setModuleId(resultSet.getString(15));
				refset.setTargetId(resultSet.getString(16));
				refset.setResetActive(Integer.parseInt(resultSet.getString(17)));

			} else {
				refset = new Refset();
				refset.setRefSetId(resultSet.getString(10));
				refset.setModuleId(resultSet.getString(11));
				refset.setTargetId(resultSet.getString(12));
				refset.setResetActive(Integer.parseInt(resultSet.getString(13)));
			}
			compositeDescription.setRefset(refset);
			compositeDescriptionList.add(compositeDescription);
		}
	}

	public List<CompositeDescription> getDomainRefset(String refsetId, long offset, long totalRecords)
			throws SQLException, ParseException, ConceptStateException, ConceptFSNException, ConceptDefException {

		properties = PropertyReader.loadSystemProperties();
		connection = ConnectionManager.getConnection();
		statement = DBUtil.getStatement(connection);
		resultSet = DBUtil.retrieveRefsetColumns(refsetId, statement, getOffset(), totalRecords);
		compositeDescriptionList = new ArrayList<CompositeDescription>();
		setRefsetList(resultSet);
		setDescriptionListForQuickSearch();
		DBUtil.closeResultSet(resultSet);
		DBUtil.closeStatement(statement);
		return compositeDescriptionList;
	}

	/**
	 * Returns list of {@link CompositeDescription}s for the provided Refset Id.
	 *
	 * @throws SQLException
	 * @throws ParseException
	 * @throws ConceptDefException
	 * @throws ConceptFSNException
	 * @throws ConceptStateException
	 */
	public List<CompositeDescription> getDomaincRefset(String refsetId, long offset, long totalRecords,
			Set<String> moduleIdSet)
			throws SQLException, ParseException, ConceptStateException, ConceptFSNException, ConceptDefException {
		properties = PropertyReader.loadSystemProperties();
		connection = ConnectionManager.getConnection();
		statement = DBUtil.getStatement(connection);
		compositeDescriptionList = new ArrayList<CompositeDescription>();
		if (refsetId.equalsIgnoreCase(Constants.CREFSET) && flag) {
			resultSet = DBUtil.retrievecRefsetColumns(refsetId, statement, getOffset(), totalRecords, moduleIdSet,
					true);
			setcRefsetList(resultSet, true);
			setDescriptionListForQuickSearch();
			flag = false;
		}
		resultSet = DBUtil.retrievecRefsetColumns(refsetId, statement, getOffset(), totalRecords, moduleIdSet, false);

		if (refsetId.equalsIgnoreCase("cRefset")) {
			setcRefsetList(resultSet, false);
			setDescriptionListForQuickSearch();
		} else {
			setRefsetList(resultSet);
			setDescriptionListForQuickSearch();
		}
		DBUtil.closeResultSet(resultSet);
		DBUtil.closeStatement(statement);
		return compositeDescriptionList;
	}

}
