/////////////////////////////////////////////////////////////////////////
//
// © University of Southampton IT Innovation Centre, 2004
//
// Copyright in this library belongs to the IT Innovation Centre of
// 2 Venture Road, Chilworth Science Park, Southampton, SO16 7NP, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created by:             Stuart E. Middleton
//      Created date:           2004/04/30
//      Created for project:    GEMSS
//
/////////////////////////////////////////////////////////////////////////
//
//      Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//      Last commit info:       $Author: $
//                              $Date: $
//                              $Revision: $
//
/////////////////////////////////////////////////////////////////////////

package uk.ac.soton.itinnovation.gemss.negotiation;

import eu.gemss.components.negotiation.ProposalHistory;
import eu.gemss.components.proxies.GEMSSProxy;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * This class implements the proposal history interface. It provides a way to store the auction history, including
 * the participants and bidding history
 */
public class ProposalHistoryImpl extends Object implements ProposalHistory {
      // member variables
      Vector mvectorParties;        // vector of GEMSSProxy instances
      Hashtable mhashProposals;     // hash of (timestamp, hash_proposal_set) entries. A proposal set is itself a hash of (party, WSLA string)
      Hashtable mhashWSLATemplates; // hash of (proxy, WSLA string) for template WSLA's
      Hashtable mhashCFPs; // hash of active CFPs (proxy,CFP string)
      Hashtable mhashFinished; // hash of finished proxies (proxy,boolean(true))
      double mnBiddingThreshold;// current bidding threshold
      long mnProposalDeadline; // deadline for proposals (-1 if not set)
      long mnAuctionDeadline; // deadlien for overall auction (-1 is not set)
      long mnMaxTimestamp;

      /**
       * constructor, make vectors
       */
      public ProposalHistoryImpl()
      {
            super();
            mvectorParties = new Vector();
            mhashProposals = new Hashtable();
            mhashWSLATemplates = new Hashtable();
            mhashCFPs = new Hashtable();
            mhashFinished = new Hashtable();
            mnBiddingThreshold = -1;
            mnProposalDeadline = -1;
            mnAuctionDeadline = -1;
            mnMaxTimestamp = 0; // timestamps go from 1 .. N, this is a starting value
      }

      /**
       * destructor
       */
      protected void finalize() throws Throwable
      {
            Enumeration enum;
            Hashtable hash;

            // explicity clear vector contents
            if( mvectorParties != null ) mvectorParties.clear();
            if( mhashCFPs != null ) mhashCFPs.clear();
            if( mhashFinished != null ) mhashFinished.clear();
            if( mhashWSLATemplates != null ) mhashWSLATemplates.clear();

            // explicitly clear hash contents
            if( mhashProposals != null ) {
                  enum = mhashProposals.elements();
                  while( enum.hasMoreElements() ) {
                        hash = (Hashtable) enum.nextElement();
                        if( hash != null ) hash.clear();
                  }
                  mhashProposals.clear();
            }
      } // finalize

      /**
       * Add a party to the auction history. Parties will participate in the auction, and be sent the relevant auction
       * messages etc.
       * Exceptions are passed on through
       * @param proxy GEMSSProxy bound to a service provider
       */
      synchronized public void addParty( GEMSSProxy proxy ) throws Exception
      {
            // check parameters
            if( proxy == null ) throw new Exception("null parameters");

            // check to see if proxy already in the party list
            if( mvectorParties.contains( proxy ) ) return;

            // add to list
            mvectorParties.addElement( proxy );

            // all done
            return;
      }

      /**
       * Add a WSLA object to the auction history. Parties will each require a WSLA before the auction can be started.
       * Exceptions are passed on through.
       * @param proxy GEMSSProxy bound to a service provider
       * @param strWSLA WSLA object
       */
      synchronized public void addWSLATemplate( GEMSSProxy proxy, String strWSLA ) throws Exception
      {
            // check parameters
            if( proxy == null || strWSLA == null ) throw new Exception("null parameters");

            // check to see if proxy already in the party list
            mhashWSLATemplates.put( proxy,strWSLA );

            // all done
            return;
      }

      /**
       * Set the active call for proposals for this proxy. The call is needed so that the proposal response can be evaluated
       * within the context of the call's constraints.
       * @param proxy GEMSSProxy bound to a service provider
       * @param strCFP call for proposal XML string
       */
      public void setCFP( GEMSSProxy proxy, String strCFP ) throws Exception
      {
            // check parameters
            if( proxy == null || strCFP == null ) throw new Exception("null parameters");

            // check to see if proxy already in the party list
            mhashCFPs.put( proxy,strCFP );

            // all done
            return;

      }

      /**
       * Add a proposal, tagged to a time stamp and participant. Normally the time stamp will be the current iteration (round)
       * of the auction.
       * Exceptions are passed on through
       * @param proxy GEMSSProxy bound to a service provider
       * @param strWSLA string representation of a web service leval agreement
       * @param nTimeStamp time stamp
       */
      synchronized public void addProposal( GEMSSProxy proxy, String strWSLA, long nTimeStamp ) throws Exception
      {
            Hashtable hashProposalSet;
            Long index;

            // check parameters
            if( proxy == null || strWSLA == null ) throw new Exception("null parameters");

            // check to see if party exists
            if( !mvectorParties.contains( proxy ) ) throw new Exception("Party does not exist");

            // does timestamp entry exist already
            index = new Long( nTimeStamp );
            if( !mhashProposals.containsKey( index ) ) {
                  // make new entry for this timestamp
                  hashProposalSet = new Hashtable();
                  mhashProposals.put( index,hashProposalSet );
            }
            else {
                  hashProposalSet = (Hashtable) mhashProposals.get( index );
                  if( hashProposalSet == null ) throw new Exception("null proposal set found");
            }

            // add WSLA to hash (replaces any old values) of proposal set
            hashProposalSet.put( proxy,strWSLA );

            // all done
            return;
      }

      /**
       * get all parties
       * Exceptions are passed on through
       * @return vector of GEMSSProxy objects
       */
      synchronized public Vector getParties() throws Exception
      {
            return mvectorParties;
      }

      /**
       * Set the bidding finished flag for a party
       * @param proxy GEMSSProxy bound to a service provider
       */
      public void setFinished( GEMSSProxy proxy ) throws Exception
      {
            // check parameters
            if( proxy == null ) throw new Exception("null parameters");

            // check to see if proxy already in the party list
            mhashFinished.put( proxy,new Boolean(true) );

            // all done
            return;

      }

      /**
       * query the bidding finished flag for a party
       * @param proxy GEMSSProxy bound to a service provider
       */
      public boolean queryFinished( GEMSSProxy proxy ) throws Exception
      {
            Boolean bFinished;

            // check parameters
            if( proxy == null ) throw new Exception("null parameters");

            // check to see if proxy already in the party list
            bFinished = (Boolean) mhashFinished.get( proxy );
            if( bFinished == null ) return false;

            // must be finished
            return true;

      }


      /**
       * Sets the current bidding threshold
       * @param nThreshold new bidding threshold
       */
      public void setBiddingThreshold( double nThreshold ) throws Exception
      {
            mnBiddingThreshold = nThreshold;
      }

      /**
       * Returns the current bidding threshold
       * @result new bidding threshold
       */
      public double getBiddingThreshold() throws Exception
      {
            return mnBiddingThreshold;
      }

      /**
       * Sets the current deadline for proposals (if any)
       * @param nDeadline time offset from 2000 GTM
       */
      public void setProposalDeadline( long nDeadline ) throws Exception
      {
            mnProposalDeadline = nDeadline;
      }

      /**
       * Get the current deadline for proposals (if any) or -1 if not
       * @return time offset from 2000 GTM
       */
      public long getProposalDeadline() throws Exception
      {
            return mnProposalDeadline;
      }

      /**
       * Sets the auction deadline, beyond which the auction must not go
       * @param nDeadline time offset from 2000 GTM
       */
      public void setAuctionDeadline( long nDeadline ) throws Exception
      {
            mnAuctionDeadline = nDeadline;
      }

      /**
       * Get the auction deadline or -1 if none
       * @return time offset from 2000 GTM
       */
      public long getAuctionDeadline() throws Exception
      {
            return mnAuctionDeadline;
      }

      /**
       * Updates the timestamp, incrementing it by one, and returns the new value.
       * The timestamp is a simple number 1...N representing the bidding round.
       * @return new timestamp
       */
      public long updateTimestamp() throws Exception
      {
            mnMaxTimestamp++;
            return getLastTimestamp();
      }

      /**
       * Returns the last timestamp. There will be timestamps from 1 .. current timestamp.
       * The timestamp is a simple number 1...N representing the bidding round.
       * @return current timestamp
       */
      public long getLastTimestamp() throws Exception
      {
            return mnMaxTimestamp;
      }

      /**
       * get all proposals at a given time stamp
       * Exceptions are passed on through
       * @param nTimeStamp time stamp
       * @return hash of (GEMSSProxy,WSLA string)
       */
      synchronized public Hashtable getProposals( long nTimeStamp ) throws Exception
      {
            Long index;

            // make index
            index = new Long( nTimeStamp );

            // get proposal set (if any) and return it
            return (Hashtable) mhashProposals.get( index );
      }

      /**
       * get WSLA template for a participant
       * Exceptions are passed on through
       * @param proxy GEMSSproxy object representing a participant
       * @return WSLA object
       */
      synchronized public String getWSLATemplate( GEMSSProxy proxy ) throws Exception
      {
            // get WSLA (if any)
            return (String) mhashWSLATemplates.get( proxy );
      }

      /**
       * Get the active (i.e. last) call for proposals for this proxy. The call is needed so that the proposal response can be evaluated
       * within the context of the call's constraints.
       * @param proxy GEMSSProxy bound to a service provider
       * @return call for proposal XML string, or null if there is none
       */
      public String getCFP( GEMSSProxy proxy ) throws Exception
      {
            // get CFP (if any)
            return (String) mhashCFPs.get( proxy );
      }

      // TODO write readObject and writeObject methods for this class ??
} // end ProposalHistoryImpl