//------------------------------------------------------------------------------
// <copyright file="Session.java" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>
//      The implementation of the Session Class
// </summary>
//------------------------------------------------------------------------------


package com.microsoft.hpc.scheduler.session;

import javax.xml.bind.JAXBElement;

import com.microsoft.hpc.exceptions.*;
import com.microsoft.hpc.sessionlauncher.*;
import com.microsoft.hpc.brokerlauncher.*;
import com.microsoft.hpc.sessionlauncher.SessionInfo;

import com.microsoft.hpc.SOATrace.SOATraceSource;
import com.microsoft.hpc.SOATrace.TraceHelper;
import com.microsoft.schemas._2003._10.serialization.arrays.ArrayOfstring;

/**
 * The jobs associated with this object will be automatically closed on disposing this object
 * 
 */
public class Session extends SessionBase
{
    /**
     * Whether the jobs will be closed on disposing this session
     */
    private Boolean autoCloseJob;
    
    /**
     * Initializes a new instance of the Session class
     * @param info session info 
     * @param headnode headnode name
     * @param autoClose if jobs will be closed on disposing
     * @param traceSource trace source
     */
    Session(SessionInfo info, String headnode, Boolean autoClose, SOATraceSource traceSource)
    {
        super(info, headnode, traceSource);
        this.autoCloseJob = !autoClose;
        TraceHelper.TraceInfo(traceSource, "Session Created.");
    }

    /**
     * Gets a value indicating whether the job will be automatically closed on disposal of this session
     * @return the autoCloseJob
     */
    public Boolean getAutoCloseJob()
    {
        return autoCloseJob;
    }

    /**
     * Sets a value indicating whether the job will be automatically closed on disposal of this session
     * @param autoCloseJob the autoCloseJob to set
     */
    public void setAutoCloseJob(Boolean autoCloseJob)
    {
        this.autoCloseJob = autoCloseJob;
    }
     
    /**
     * Gets the Net.Tcp endpoint reference for load balancer of this session
     * @return endpoint address
     * @deprecated Use EndpointReference instead.
     */
    public String netTcpEndpointReference()
    {
        if(this.getInfo().getTransportScheme().get(0) != "NetTcp")
        {
            return null;
        }
        else
        {
            return generateEndpointAddress(this.getInfo().getBrokerEpr(), TransportScheme.NetTCP);
        }
    }
    
    /**
     * Gets the Http endpoint reference for load balancer of this session
     * @return endpoint address
     * @depreciated Use EndpointReference instead
     */
    public String httpEndpointReference()
    {
        if(this.getInfo().getTransportScheme().get(0) != "Http")
        {
            return null;
        }
        else
        {
            return generateEndpointAddress(this.getInfo().getBrokerEpr(), TransportScheme.Http);
        }
    }
    
    //public ISchedulerJob BrokerJob
    //      We don't have broker job anymore
    
    //public static IAsyncResult BeginCreateSession(SessionStartInfo startInfo, AsyncCallback callback, Object state)
    //public static Session EndCreateSession(IASyncResult result)
    //public static void CancelCreateSession(IAsyncResult result)
    //      Asynchronous is unsupported in java
    
    /**
     * Synchronous mode of submitting a job and get a ServiceJobSession object
     * @param startInfo the session start info for creating the service session
     * @return A service job session object, including the endpoint address and the two jobs related to this session
     * @throws SessionException if an exception occurred during session creation
     * @throws TimeoutException if a timeout occurred during creation
     */
    public static Session createSession(SessionStartInfo startInfo) 
    throws TimeoutException, SessionException
    {
        return createSession(startInfo, Timeout.Infinite);
    }
    
    /**
     * Synchronous mode of submitting a job and get a ServiceJobSession object.
     * If a session object hasn't been returned within a timeout, the method will throw a timeout exception
     * @param startInfo the session start info for creating the service session
     * @param timeout the timeout
     * @return A service job session object, including the endpoint address and the two jobs related to this session  
     * @throws SessionException if an exception occurred during session creation
     * @throws TimeoutException if a timeout occurred during creation
     */
    public static Session createSession(SessionStartInfo startInfo, Timeout timeout)
    throws TimeoutException, SessionException
    {
        return (Session)createSessionInternal(startInfo, Timeout.Infinite, false);
    }
    
    /**
     * Synchronous mode of submitting a job and get a ServiceJobSession object.
     * If a session object hasn't been returned within a timeout, the method will throw a timeout exception
     * @param startInfo the session start info for creating the service session
     * @param timeout the timeout in milliseconds
     * @return A service job session object, including the endpoint address and the two jobs related to this session.  
     * @throws SessionException if an exception occurred during session creation
     * @throws TimeoutException if a timeout occurred during creation
     */
    public static Session createSession(SessionStartInfo startInfo, int timeoutMilliseconds)
    throws TimeoutException, SessionException 
    {
        return (Session)createSessionInternal(startInfo, timeoutMilliseconds, false);
    }
    
    /**
     * This method closes the session with the given ID
     * @param headNode  headnode name
     * @param sessionId session Id
     * @throws SessionException  thrown if an error occurred while trying to get session launcher 
     */
    public static void closeSession(String headNode, int sessionId) throws SessionException
    {
        Utility.throwIfNullOrEmpty(headNode, "headNode");
        
        ISessionLauncher client = null;
        IBrokerLauncher broker = null;
        
        try
        {
            client = getSessionLauncher(headNode);
            
            SessionInfo info = client.getInfo(headNode, "https://", sessionId);
            broker = getBrokerLauncher(info.getBrokerLauncherEpr().getValue());
            broker.close(sessionId);
        }
        catch(ISessionLauncherGetInfoSessionFaultFaultFaultMessage e)
        {
            Utility.translateFaultException(e.getFaultInfo());
        }
        catch(IBrokerLauncherCloseSessionFaultFaultFaultMessage e)
        {
            Utility.translateFaultException(e.getFaultInfo());
        }
        finally
        {
            //SOATraceSource traceSource = new SOATraceSource(Integer.toString(sessionId), SessionBase.getTraceSourceName(), SessionBase.getEventSource());
            if( client != null)
            {
                ;//SafeClose?
            }
            if( broker!= null)
            {
                ;//SafeClose?
            }
        }
    }
    
    /**
     * Attach to an existing session with the session id
     * @param attachInfo the attach info
     * @return A persistent session
     * @throws SessionException if an exception was thrown during attach
     */
    public static Session attachSession(SessionAttachInfo attachInfo)
    throws SessionException, TimeoutException
    {
        return attachSession(attachInfo, Timeout.Infinite);
    }
    
    /**
     * Attach to an existing session with session id    
     * @param attachInfo the attach info 
     * @param timeout timeout
     * @return  a persistent session
     * @throws SessionException if an exception was thrown during attach
     */
    public static Session attachSession(SessionAttachInfo attachInfo, Timeout timeout)
    throws SessionException, TimeoutException
    {
        SOATraceSource traceSource = new SOATraceSource(Integer.toString(attachInfo.getId()), SessionBase.getTraceSourceName());
        SessionInfo info =  attachInternal(attachInfo, timeout, traceSource);
        return new Session(info, attachInfo.getHeadnode(), true, traceSource);
    }
    
    /**
     * Attach to an existing session with session id    
     * @param attachInfo the attach info 
     * @param timeoutMilliseconds timeout
     * @return  a persistent session
     * @throws SessionException if an exception was thrown during attach
     */
    public static Session attachSession(SessionAttachInfo attachInfo, int timeoutMilliseconds)
    throws SessionException, TimeoutException
    {
        SOATraceSource traceSource = new SOATraceSource(Integer.toString(attachInfo.getId()), SessionBase.getTraceSourceName());
        SessionInfo info =  attachInternal(attachInfo, timeoutMilliseconds, traceSource);
        return new Session(info, attachInfo.getHeadnode(), true, traceSource);
    }
    
    protected void finalize()
    {
       dispose();
    }
     
    /**
     * Dispose the service job if autoclose is true
     */
    public void dispose()
    {
        if (autoCloseJob)
        {
            IBrokerLauncher broker = null;
            try
            {
                broker = getBrokerLauncher(this.getInfo().getBrokerLauncherEpr().getValue());
                broker.close(this.getId());
            }
            catch (Exception e)
            {
                TraceHelper.TraceException(this.getTraceSource(), e);
            }
            finally
            {
                if (broker != null)
                {
                    ;
                }
            }
        }
    }   
    
    
    /**
     * Generate endpoint address by scheme from epr list
     * @param eprList indicating the epr list
     * @param scheme indicating the scheme
     * @return endpoint address
     */
    private static String generateEndpointAddress(JAXBElement<ArrayOfstring> eprList, TransportScheme scheme)
    {
        int index = scheme.getIndex();
        return eprList.getValue().getString().get(index);
    }
    
}
