/*******************************************************************************
 *  Copyright 2017-2018 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 cdac.medinfo.sdk.dcm30_04.dicommodel.modules;



import cdac.medinfo.sdk.dcm30_04.baselibs.Tag;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITag;
import cdac.medinfo.sdk.dcm30_04.enums.EnumAcquisitionTimeSynchronized;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSynchronizationTrigger;
import cdac.medinfo.sdk.dcm30_04.enums.EnumTimeDistributionProtocol;

import cdac.medinfo.sdk.dcm30_04.exceptions.InvalidModuleException;
import cdac.medinfo.sdk.dcm30_04.exceptions.MandatoryMissingException;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

// TODO: Auto-generated Javadoc
/**
 \* This module specifies the Attributes necessary to uniquely identify a frame of reference that
 * establishes the temporal relationship of SOP Instances.
 */
public class SynchronizationModule extends Module  
{


	/**
	 * The obj single collection.
	 */
	public static ISingleCollection<ITag> objSingleCollection = null;


	/**
	 * Instantiates a new synchronization module.
	 * 
	 * @param objIDataSet the obj i data set
	 */
	public SynchronizationModule(IDataSet objIDataSet)
	{
		super(objIDataSet);
	}

	static
	{
		objSingleCollection = new SingleCollection<ITag>();
		objSingleCollection.add(new Tag(0x0018,0x1061));
		objSingleCollection.add(new Tag(0x0018,0x106A));
		objSingleCollection.add(new Tag(0x0018,0x106C));
		objSingleCollection.add(new Tag(0x0018,0x1800));
		objSingleCollection.add(new Tag(0x0018,0x1801));
		objSingleCollection.add(new Tag(0x0018,0x1802));
		objSingleCollection.add(new Tag(0x0018,0x1803));
		objSingleCollection.add(new Tag(0x0020,0x0200));
	}

	/**
	 * This method validates each Attribute in the Module according to the Type
	 * of the Attribute.Attributes are of 5 types.
	 * Type 1,Type 2 are Mandatory:
	 * Mandatory Attributes have to present in the Module.
	 * Type 1C,2C are Conditional:
	 * Conditional Attributes' presence depend on a condition.
	 * If the condition is satisfied the Attribute has to be present.
	 * Type 3 are Optional
	 * Optional Attributes can be added as and when required.
	 * 
	 * @return Boolean - status indicating success or failure
	 * 
	 * @throws InvalidModuleException - If validation of Module fails
	 */
	public  boolean validateModule() throws InvalidModuleException
	{

		try
		{		
			//Check Mandatory Elements Type 1,2
			if(!isPresent(0x0020,0x0200))
				throw new MandatoryMissingException("0010,0200");
			else if(!isPresent(0x0018,0x106A))
				throw new MandatoryMissingException("0010,106A");
			else if(!isPresent(0x0018,0x1800))
				throw new MandatoryMissingException("0010,1800");

			/*
			 * (0018,106C) Synchronization Channel - Condition not clear
			 * Required if synchronization channel or trigger is encoded in a waveform in this SOP Instance
			 * plz refer pdf Chapter 3 page no - 263
			 */
		}
		catch(MandatoryMissingException mme)
		{
			if(DicomConfig.createInstance().isLoggingOn())
				DicomLogger.getLogger().log(mme.getMessage());

			
				throw new InvalidModuleException(this.getClass().getSimpleName(),mme);

		}
		return true;
	}

	/**
	 * Sets UID of common synchronization environment.A set of equipment may share a common
	 * acquisition synchronization environment, which is identified by a Synchronization
	 * Frame of Reference UID.
	 * 
	 * @param strSynchronizationFrameOfReferenceUID - String valuer of Synchronization Frame of Reference UID
	 */
	public void setSynchronizationFrameOfReferenceUID(String strSynchronizationFrameOfReferenceUID)
	{
		/*Accept Synchronization Frame of Reference UID in String format of type UI.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		addDataElement(0x0020, 0x0200, DicomConstants.DCM_DT_UI, strSynchronizationFrameOfReferenceUID);
	}

	/**
	 * Sets Data acquisition synchronization with external equipment.
	 * Enumerated Values: SOURCE - this equipment provides synchronization channel or trigger to other equipment
	 * ,EXTERNAL - this equipment receives synchronization channel or trigger from other equipment
	 * ,PASSTHRU - this equipment receives synchronization channel or trigger and forwards it
	 * ,NO TRIGGER - data acquisition not synchronized by common channel or trigger
	 * 
	 * @param enumSynchronizationTrigger - Enum value of Synchronization Trigger.
	 */
	public void setSynchronizationTrigger(EnumSynchronizationTrigger enumSynchronizationTrigger)
	{
		/*Accept Synchronization Trigger in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		addDataElement(0x0018, 0x106A, DicomConstants.DCM_DT_CS, enumSynchronizationTrigger.getValue());
	}

	/**
	 * Sets value that Specifies equipment ID of trigger source and/or type of trigger.
	 * 
	 * @param strTriggerSourceOrType - String value of Trigger Source or Type
	 */
	public void setTriggerSourceOrType(String strTriggerSourceOrType)
	{
		/*Accept Trigger Source Or Type in String format of type LO.
		 * Read the Transfer Syntax and check to create ImplicitDE or ExplicitDE .
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the Hash Map
		 */
		addDataElement(0x0018, 0x1061, DicomConstants.DCM_DT_LO, strTriggerSourceOrType);
	}

	/**
	 * Sets Identifier of waveform channel that records the synchronization channel or trigger.
	 * Required if synchronization channel or trigger is encoded in a waveform in this SOP Instance
	 * 
	 * @param arrShSynchronizationChannel - short array of Synchronization Channel
	 */
	public void setSynchronizationChannel(short[] arrShSynchronizationChannel)
	{
		/*Accept Synchronization Channel in Short format of type US.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		addDataElement(0x0018, 0x106C, DicomConstants.DCM_DT_US, arrShSynchronizationChannel);
	}

	/**
	 * Sets Acquisition Datetime (0008,002A) synchronized with external time reference.
	 * Enumerated Values: Y, N.
	 * 
	 * @param enumAcquisitionTimeSynchronized - enum value of Acquisition Time Synchronized
	 */
	public void setAcquisitionTimeSynchronized(EnumAcquisitionTimeSynchronized enumAcquisitionTimeSynchronized)
	{
		/*Accept Acquisition Time Synchronized in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		String strAcquisitionTimeSynchronized = enumAcquisitionTimeSynchronized.getValue();
		addDataElement(0x0018, 0x1800, DicomConstants.DCM_DT_CS, strAcquisitionTimeSynchronized);
	}

	/**
	 * Sets ID of equipment or system providing time reference.
	 * 
	 * @param strTimeSource - String value of Time Source
	 */
	public void setTimeSource(String strTimeSource)
	{
		/*Accept Time Source in String format of type SH.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		addDataElement(0x0018, 0x1801, DicomConstants.DCM_DT_SH, strTimeSource);
	}

	/**
	 * Sets Method of time distribution used to synchronize this equipment.
	 * Defined Terms: NTP - Network Time Protocol,IRIG - InterRange Instrumentation Group,
	 * GPS - Global Positioning System, SNTP Simple Network Time Protocol
	 * 
	 * @param enumTimeDistributionProtocol the enum time distribution protocol
	 */
	public void setTimeDistributionProtocol(EnumTimeDistributionProtocol enumTimeDistributionProtocol)
	{
		/*Accept Time Distribution Protocol in String format of type CS.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		String strTimeDistributionProtocol = enumTimeDistributionProtocol.getValue();
		addDataElement(0x0018, 0x1802, DicomConstants.DCM_DT_CS, strTimeDistributionProtocol);
	}

	/**
	 * Sets IP Address of NTP time source. IPv4 addresses shall be in dotted decimal (e.g. 192.168.1.1). The IPv6
	 * addresses shall be in colon separated hexadecimal (e.g. 12:34:56:78:9a:bc:de:f0).
	 * 
	 * @param strNTPSourceAddress - String value of NTP Source Address
	 */
	public void setNTPSourceAddress(String strNTPSourceAddress)
	{
		/*Accept NTP Source Address in String format of type LO.
		 * Read the Transfer Syntax and check if ImplicitDE or ExplicitDE to create.
		 * Set the iGroupNumber and iElementNumber to ImplicitDE object 
		 * Set the iVRType
		 * Set length from the element
		 * Add this element to the DataSet
		 */
		addDataElement(0x0018, 0x1803, DicomConstants.DCM_DT_LO, strNTPSourceAddress);
	}

	/**
	 * Returns UID of common synchronization environment.
	 * 
	 * @return String - String value of Synchronization Frame Of Reference UID.
	 */
	public String getSynchronizationFrameOfReferenceUID()
	{Object objectValue = getValue(0x0020,0x0200);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Returns Data acquisition synchronization with external equipment.
	 * 
	 * @return String - String value of Synchronization Trigger.
	 */
	public String getSynchronizationTrigger()
	{
		 Object objValue = getValue(0x0018,0x106A);
   if(objValue!=null)
      return objValue.toString();
   return null;

	}

	/**
	 * Returns Specifies equipment ID of trigger source and/or type of trigger.
	 * 
	 * @return String - String value of equipment ID of trigger source and/or type of trigger
	 */
	public String getTriggerSourceOrType()
	{Object objectValue = getValue(0x0018,0x1061);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Returns Identifier of waveform channel that records the synchronization channel or trigger.
	 * 
	 * @return short[] - short array of Synchronization Channel
	 */
	public short[] getSynchronizationChannel()
	{
		Object objectValue = getValue(0x0018,0x106C);
		if(objectValue!=null)
			return (short[])objectValue;
		return null;
	}

	/**
	 * Returns Acquisition Datetime (0008,002A) synchronized with external time reference.
	 * 
	 * @return String - String value of Acquisition Time Synchronized
	 */
	public String getAcquisitionTimeSynchronized()
	{
		Object objValue = getValue(0x0018,0x1803);
		if(objValue != null)
			return objValue.toString();
		return null;
	}

	/**
	 * Returns ID of equipment or system providing time reference.
	 * 
	 * @return String - String value of Time Source.
	 */
	public String getTimeSource()
	{Object objectValue = getValue(0x0018,0x1801);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Returns Method of time distribution used to synchronize this equipment.
	 * 
	 * @return String - String value of Time Distribution Protocol.
	 */
	public String getTimeDistributionProtocol()
	{Object objectValue = getValue(0x0018,0x1802);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/**
	 * Returns IP Address of NTP time source.
	 * 
	 * @return String - String value of NTP Source Address
	 */
	public String getNTPSourceAddress()
	{Object objectValue = getValue(0x0018,0x1803);
		if(objectValue!=null)
			return objectValue.toString();
		return null;
	}

	/* 
	 * I have modified the collection type from vector to custom class
	 * This method is used by the Module Iterator to iterate through the DataSet and return only
	 * those elements that belong to the respective Module class whose getVectorOfKeys is called.
	 */
	/**
	 * This method returns the vector of keys representing the DataElements
	 * that belong to this module.
	 * 
	 * @return vector of Tags - returns the vector containing the collection of tags
	 */
	public ISingleCollection<ITag> getVectorOfKeys()
	{
		return objSingleCollection;
	}


}
