/*******************************************************************************
 *  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.scu.commons;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Locale;


import cdac.medinfo.sdk.dcm30_04.services.association.AgreedAssociation;
import cdac.medinfo.sdk.dcm30_04.services.association.IDIMSEAssociation;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IMessageListener;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.ServiceMessageEvent;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomLogger;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ResourceBundleWrapper;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;

/**
 * This abstract class is extended by all SCU. It also implements Message Listener i.e.
 * all the response will be notified to SCU.
 */
public abstract class SCU implements IMessageListener 
{

	/** Instance of Dicom Message RSP collection*/
	protected ISingleCollection<DicomMessage> objDIMSERSPCollection ;

	/**Instance of SCU Session*/
	protected SCUSession objSCUSession = null;

	/**Instance of INet Socket Address*/
	protected InetSocketAddress objInetSocketAddress;

	/**Instance of Agreed Association*/
	protected AgreedAssociation objAgreedAssociation;

	/**Instance of Dimse Association*/
	protected IDIMSEAssociation objIDimseAssociation;

	/**boolean variable representing association status*/
	protected boolean associateStatus;

	/** boolean variable representing whether response is received or not*/
	protected boolean isResponseReceived;

	/**
	 * Instantiates a new SCU.
	 * @param objSCUSession instance of SCU Session.
	 */
	public SCU(SCUSession objSCUSession)
	{
		this.objSCUSession = objSCUSession;
		objIDimseAssociation = objSCUSession.getDIMSEAssociation();
		associateStatus = objSCUSession.getAssociationStatus();
		objDIMSERSPCollection = new SingleCollection<DicomMessage>();
		objAgreedAssociation = objSCUSession.getAgreedAssociation();
	}

	/**
	 * Instantiates a new SCU.
	 * @param addr INet Socket Address.
	 * @throws IOException Signals if an IO Exception occurred.
	 */
	public SCU(InetSocketAddress addr) throws IOException
	{
		this.objInetSocketAddress = addr;
		objDIMSERSPCollection = new SingleCollection<DicomMessage>();
	}
	
	/**
	 * Sets Response Collection
	 * @param objResponseList collection of Dicom message containing response.
	 */
	public void setDIMSEResponse(ISingleCollection<DicomMessage> objResponseList)
	{
		this.objDIMSERSPCollection = objResponseList; 
	}

	/**
	 * Retrieves Response Collection.
	 * @return ISingleCollection<DicomMessage> - collection of Dicom message containing response.
	 */
	public ISingleCollection<DicomMessage> getDIMSEResponse()
	{
		return objDIMSERSPCollection;
	}

	/**
	 * Receives response.
	 * @param objServiceMessageEvent object of Service Message Event. 
	 * This Event is fired when the response is received from SCP.
	 */
	public void receiveMessage(ServiceMessageEvent objServiceMessageEvent) throws IOException
	{
		DicomMessage objDicomMessage = objServiceMessageEvent.getDicomMessge();
		if(DicomConfig.createInstance().isLoggingOn())
		{
			DicomLogger objDicomLogger = DicomLogger.getLogger();
			objDicomLogger.log(ResourceBundleWrapper.getValue("status", "ResponseReceived",new Locale(DicomConfig.createInstance().getLocale())) + objDicomMessage.getCommandType().name());
			objDicomLogger.log(objDicomMessage.getCommandType().name()+" "+ResourceBundleWrapper.getValue("status", "StatusCode", new Locale(DicomConfig.createInstance().getLocale()))+ getStatus(objDicomMessage));
		}
		objDicomMessage.getDataSet();
		objSCUSession.getServiceAgent().dispose();
		objDIMSERSPCollection.add(objDicomMessage);
		isResponseReceived = true;
		if(objAgreedAssociation == null)
			objAgreedAssociation = objSCUSession.getAgreedAssociation();
		synchronized(this)
		{
			if(!objAgreedAssociation.isAsyncMode())
			{
				this.notify();
			}
		}
	}

	private String getStatus(DicomMessage objDicomMessage)
	{
		Object objValue = objDicomMessage.getValue(0x0000,0x0900);
		if(objValue != null)
		{
			short shValue = Short.parseShort(objValue.toString());
			String strHexValue = Integer.toHexString(shValue);
			return strHexValue;
		}
		return null;
	}
	/**
	 * Send response.
	 * @param objDicomMessge instance of Dicom Message.
	 */
	public abstract boolean sendMessage(DicomMessage objDicomMessge) throws IOException;

	/**
	 * Sets the association status.
	 * @param status boolean variable representing status of association.
	 * true - if association is alive.
	 * false - if association does not exits.
	 */
	public void setAssociationStatus(boolean status)
	{
		associateStatus = status;
		synchronized(this)
		{
			if(!associateStatus)
			{
				this.notify();
			}
		}
	}

	/**
	 * Sets DimseAssociation which also shows status of current association.
	 * @param objIDIMSEAssociation instance of IDIMSEAssociation
	 */
	public void setDIMSEAssociation(IDIMSEAssociation objIDIMSEAssociation)
	{
		this.objIDimseAssociation = objIDIMSEAssociation; 
	}

	/**
	 * Retrieves DimseAssociation which also shows status of current association.
	 * @return IDIMSEAssociation - instance of IDIMSEAssociation
	 */
	public IDIMSEAssociation getDIMSEAssociation()
	{
		return objIDimseAssociation;
	}
}
