/*******************************************************************************
 *  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.services.onlineelectronicstoragesecureuse;

import java.io.IOException;


import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDicomValue;
import cdac.medinfo.sdk.dcm30_04.enums.EnumSOPInstanceStatus;
import cdac.medinfo.sdk.dcm30_04.exceptions.ParseException;
import cdac.medinfo.sdk.dcm30_04.utils.EnumFeatureList;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;

/**
 * This class will be used as an add-on by SCU and SCP of the storage service classes
 */
public class OnlineElectronicStorageSecureUseProfile 
{
	

	private static OnlineElectronicStorageSecureUseProfile objSecureUseProfile = null;


	private boolean bIsProfileSupportedAndEnabled = false;
	private boolean bIsSecureConnection = false;

	// collection of those SOPInstanceUIDs for which the StorageCommitment Confirmation is Expected. 
	private ISingleCollection<String> objSOPInstanceCollection = new SingleCollection<String>();
	/**
	 * Constructor for the OnlineElectronicStorageSecureUseProfile
	 */
	private OnlineElectronicStorageSecureUseProfile()
	{

	}
	/**
	 * getOnlineElectronicStorageSecureUseProfile return object of OnlineElectronicStorageSecureUseProfile
	 * @return objSecureUseProfile
	 */
	public static synchronized  OnlineElectronicStorageSecureUseProfile getOnlineElectronicStorageSecureUseProfile()
	{
		if(objSecureUseProfile == null)
		{
			synchronized (OnlineElectronicStorageSecureUseProfile.class) 
			{
				if(objSecureUseProfile == null)
					objSecureUseProfile = new OnlineElectronicStorageSecureUseProfile();	
			}
		}
		return objSecureUseProfile;
	}

	/**
	 * boolean value of the is contains strSOPInstanceUID
	 * @param strSOPInstanceUID
	 * @return boolean value of the contain strSOPInstanceUID 
	 */
	public boolean isStorageCommitmentConfirmationExpected(String strSOPInstanceUID)
	{
		return objSOPInstanceCollection.contains(strSOPInstanceUID);
	}

	/**
	 * boolean value of the remove strSOPInstanceUID
	 * @param strSOPInstanceUID
	 * @return
	 */
	public boolean finalise(String strSOPInstanceUID)
	{
		if(objSOPInstanceCollection.contains(strSOPInstanceUID))
		{
			objSOPInstanceCollection.remove(strSOPInstanceUID);
			System.out.println("Finalised "+ strSOPInstanceUID );
			return true;
		}
		else
		{
			System.out.println("Invalid Finalisation Request "+ strSOPInstanceUID );
			return false;
		}
	}
	/**
	 * getSOPInstanceUIDsRequired
	 * @return objSOPInstanceCollection
	 */
	public ISingleCollection<String> getSOPInstanceUIDsRequired()
	{
		return objSOPInstanceCollection;
	}

	/**
	 * isEnable 
	 * @return boolean value of the bIsProfileSupportedAndEnabled
	 */

	public boolean isEnabled() 
	{
		return bIsProfileSupportedAndEnabled;
	}


	/**
	 * method enable
	 * @param bIsEnable
	 * @return nothing
	 */
	public void enable(boolean bIsEnable)
	{
		bIsProfileSupportedAndEnabled = bIsEnable;
	}

	/**
	 * method isSecureConnection
	 * @return boolean value of the 
	 */

	public boolean isSecureConnection() {
		return bIsSecureConnection;
	}


	/**
	 * set the connection
	 * @param isSecureConnection
	 */
	public void setSecureConnection(boolean isSecureConnection) {
		bIsSecureConnection = isSecureConnection;
	}


	/**
	 * The method modifies DicomMessage in accordance with the secure storage use profile rules.
	 * @param objDicomMessage 
	 * @param bPersistOrigial - true - if Originals should be kept unchanged , This is the probable case where confirmations will be expected
	 * @return boolean - true- if storageCommitment confirmation Expected
	 * @throws ParseException
	 * @throws IOException
	 */
	public EnumSecureStorageStatus secureDataSetForStorage(IDataSet objDataSet,boolean bPersistOrigial) throws ParseException, IOException
	{
		// if profile is not supported , there is nothing to do.
		if(isEnabled() == false)
			return EnumSecureStorageStatus.PROFILE_DISABLED;

		String strSOPInstanceStatus = null;
		String strSOPInstanceUID = null;//0008,0018
		if(objDataSet==null)
			return EnumSecureStorageStatus.INVALID_DATASET;
		else
		{
			strSOPInstanceStatus = (String)objDataSet.getValue(0x0100, 0x0410);
			strSOPInstanceUID = (String)objDataSet.getValue(0x0008, 0x0018);
			if(strSOPInstanceStatus==null)
				return EnumSecureStorageStatus.NotSpecified;
			if(strSOPInstanceUID == null)
				return EnumSecureStorageStatus.INVALID_DATASET;
			if(true == objSOPInstanceCollection.contains(strSOPInstanceUID))
				return EnumSecureStorageStatus.DUPLICATE_SOPINSTANCE;
		}
		EnumSOPInstanceStatus enumSOPInstanceStatus = StandardMethods.getSOPInstanceStatus(strSOPInstanceStatus);
		if(enumSOPInstanceStatus == null)
			return EnumSecureStorageStatus.INVALID_DATASET;

		IDataSet secureStorageDataSet =  objDataSet;
		IDataElement secureStorageDataElement =  secureStorageDataSet.getDataForTag(0x0100, 0x0410);
		IDicomValue objSecureStorageDicomValue = secureStorageDataElement.getDicomValue();

		switch(enumSOPInstanceStatus)
		{
		case NotSpecified: // Need not to care about..
			return EnumSecureStorageStatus.STORAGECOMMITMENTNOTEXPECTED;
		case AuthorizedCopy:
			// on SecureConnection use the original message as it is.
			// on UnSecureConnection send the message as NS. 
			if(isSecureConnection()==false)
				objSecureStorageDicomValue.setValue(EnumSOPInstanceStatus.NotSpecified.getValue());
			return EnumSecureStorageStatus.STORAGECOMMITMENTNOTEXPECTED; 
		case Original:
			// on SecureConnection & Originality should be kept, then return the Original
			// otherwise send Message as NS	
			if(isSecureConnection()==true)
			{
				if(bPersistOrigial)
				{
					objSOPInstanceCollection.add(strSOPInstanceUID);
					return EnumSecureStorageStatus.STORAGECOMMITMENTEXPECTED;
				}
			}
			objSecureStorageDicomValue.setValue(EnumSOPInstanceStatus.NotSpecified.getValue());
			return EnumSecureStorageStatus.STORAGECOMMITMENTNOTEXPECTED; 

		case AuthorizedOriginal:
			// on SecureConnection & Originality should be kept, then return the Original
			// otherwise send Message as AC if Connection is secured else NS.
			EnumSOPInstanceStatus enumstorageSOPInstanceStatus;
			if(isSecureConnection()==true)
			{
				if(bPersistOrigial)
				{
					objSOPInstanceCollection.add(strSOPInstanceUID);
					return EnumSecureStorageStatus.STORAGECOMMITMENTEXPECTED;
				}
				else
					enumstorageSOPInstanceStatus = EnumSOPInstanceStatus.AuthorizedCopy;
			}
			else
			{
				enumstorageSOPInstanceStatus = EnumSOPInstanceStatus.NotSpecified;
			}
			objSecureStorageDicomValue.setValue(enumstorageSOPInstanceStatus.getValue());
			return EnumSecureStorageStatus.STORAGECOMMITMENTNOTEXPECTED;	
			default :
				return EnumSecureStorageStatus.NO_VALUE;
		}
	}

	/**
	 * This method gives the status of the EnumSecureStorageStatus
	 * @param objDataSet
	 * @return boolean - true : if Dataset modified
	 * @throws ParseException
	 * @throws IOException
	 */
	public EnumSecureStorageStatus finalise(IDataSet objDataSet) throws ParseException, IOException
	{
		boolean bPersistOrigial = false;
//		if profile is not supported , there is nothing to do.
		if(isEnabled() == false)
			return EnumSecureStorageStatus.PROFILE_DISABLED;

		String strSOPInstanceStatus = null;
		String strSOPInstanceUID = null;//0008,0018
		if(objDataSet==null)
			return EnumSecureStorageStatus.INVALID_DATASET;
		else
		{
			strSOPInstanceStatus = (String)objDataSet.getValue(0x0100, 0x0410);
			if(strSOPInstanceStatus==null)
				return EnumSecureStorageStatus.NotSpecified;
			strSOPInstanceUID = (String)objDataSet.getValue(0x0008, 0x0018);
			if(strSOPInstanceUID == null)
				return EnumSecureStorageStatus.INVALID_DATASET;
			if(false == objSOPInstanceCollection.contains(strSOPInstanceUID))
				return EnumSecureStorageStatus.INVALID_SOPINSTANCE;

		}
		EnumSOPInstanceStatus enumSOPInstanceStatus = StandardMethods.getSOPInstanceStatus(strSOPInstanceStatus);
		if(enumSOPInstanceStatus == null)
			return EnumSecureStorageStatus.INVALID_DATASET;

		IDataSet secureStorageDataSet =  objDataSet;
		IDataElement secureStorageDataElement =  secureStorageDataSet.getDataForTag(0x0100, 0x0410);
		if(secureStorageDataElement==null)
			return EnumSecureStorageStatus.NotSpecified;
		IDicomValue objSecureStorageDicomValue = secureStorageDataElement.getDicomValue();

		switch(enumSOPInstanceStatus)
		{
		case Original:
			// on SecureConnection & Originality should be kept, then return the Original
			// otherwise send Message as NS		

			if(isSecureConnection()==true)
			{
				if(bPersistOrigial)
				{
					objSOPInstanceCollection.remove(strSOPInstanceUID);
					return EnumSecureStorageStatus.FINALISATION_SUCCESSFUL;
				}
			}
			objSecureStorageDicomValue.setValue(EnumSOPInstanceStatus.NotSpecified.getValue());
			return EnumSecureStorageStatus.FINALISATION_SUCCESSFUL;

		case AuthorizedOriginal:
			// on SecureConnection & Originality should be kept, then return the Original
			// otherwise send Message as AC if Connection is secured else NS.
			EnumSOPInstanceStatus enumstorageSOPInstanceStatus;
			if(isSecureConnection()==true)
			{
				if(bPersistOrigial)
				{
					objSOPInstanceCollection.remove(strSOPInstanceUID);
					return EnumSecureStorageStatus.FINALISATION_SUCCESSFUL;
				}
				else
					enumstorageSOPInstanceStatus = EnumSOPInstanceStatus.AuthorizedCopy;
			}
			else
			{
				enumstorageSOPInstanceStatus = EnumSOPInstanceStatus.NotSpecified;
			}
			objSecureStorageDicomValue.setValue(enumstorageSOPInstanceStatus.getValue());
			return EnumSecureStorageStatus.FINALISATION_SUCCESSFUL;
		}
		return EnumSecureStorageStatus.FINALISATION_SUCCESSFUL;
	}
}
