/////////////////////////////////////////////////////////////////////////
//
// © Institute for Software Science, University of Vienna, 2004
//
// Copyright in this software belongs to Institute for Software Science, 
// University of Vienna, Nordbergstrasse 15/C/3, 1090 Vienna, Austria
//
// 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 :		Rainer Schmidt
//	Created Date :		2004/08/15
//	Created for Project:	GEMSS
//
////////////////////////////////////////////////////////////////////////
//
// Dependencies: None
//
/////////////////////////////////////////////////////////////////////////
//
//	Last commit info:	$Author: gerry $
//					$Date: 2004/08/13 10:47:08 $
//					$Revision: 1.3 $
//
/////////////////////////////////////////////////////////////////////////

package at.ac.univie.iss.proxies.qos.examples;

/**
 * Example 3/3
 * This example uses discovery to find appropriate services. After 
 * QoS negotioation with each service the cheapest is selected and
 * a job is executed.
 * ------------------
 * JobHandling    [+] 
 * QoSNegotiation [+]
 * Discovery      [+]
 */

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Vector;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
import java.util.*;
import java.text.*;

import eu.gemss.GEMSS;
import eu.gemss.GridException;
import eu.gemss.components.ComponentManager;  
import eu.gemss.components.transport.GEMSSTransportAndMessaging; 
import eu.gemss.components.proxies.qos.QoSProxy;

import eu.gemss.components.discovery.Attribute;
import eu.gemss.components.discovery.Discovery;
import eu.gemss.components.discovery.ServiceDescription;
import eu.gemss.components.discovery.DiscoveryGridException;
import eu.gemss.components.discovery.RegistryGridException;
import eu.gemss.components.ServiceRequest;
import eu.gemss.components.proxies.qos.GenericProxyRequest;
import eu.gemss.components.proxies.GEMSSProxyRequest;
import eu.gemss.components.proxies.GEMSSProxy;

import at.ac.univie.iss.proxies.qos.util.PropertiesHandler;
import at.ac.univie.iss.descriptors.qos.QoSDescriptor;
import at.ac.univie.iss.descriptors.qos.QoSDescriptorImpl;
import at.ac.univie.iss.descriptors.qos.RequestDescriptor;
import at.ac.univie.iss.descriptors.qos.RequestDescriptorImpl;


public class BasicQoSExample extends DiscoveryExample {
    
    private static Logger logger = Logger.getLogger(BasicQoSExample.class.getName());

    // sample request descriptor parameters    
    String[] reqDsc_perfParam1 = {"TESTPARAM", "100"};

    // qos descriptor parameters (price, begin and end time)
    double qosDsc_price = 200;
    Calendar qosDsc_begin = null;
    Calendar qosDsc_end = null;
    
    // QoS Proxy component
    QoSProxy qosProxy = null;
        
    public BasicQoSExample() {

        super();
        
        // get current date/time for begin and end

        qosDsc_begin = Calendar.getInstance();
        qosDsc_end = Calendar.getInstance();

        // adjust end time in +1 day
        qosDsc_end.set(Calendar.DAY_OF_MONTH,qosDsc_end.get(Calendar.DAY_OF_MONTH) + 1);

        try {
        	// write a temporary property file for manipulation
            propertiesHandler.loadProperties(endPointBase);
            propertiesHandler.saveProperties(endPointTemp);
            
            // use GEMSSProxyRequest or GenericProxyRequest
            GenericProxyRequest greq = new GenericProxyRequest(endPointTemp, "eu.gemss.components.proxies.qos.QoSProxy", null, null);
            qosProxy = (QoSProxy) cm.getInstance(greq);     
            // or use default values without property file
            // QoSProxy qosProxy = (QoSProxy) cm.getInstance("eu.gemss.components.proxies.qos.QoSProxy");

        } catch (eu.gemss.GridException ge) {
            logger.log(Level.SEVERE, "An error occured!", ge);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }

    }   
    
    final public static void main(String[] args) {
        
        BasicQoSExample basicQoSExample = new BasicQoSExample();

        logger.log(Level.INFO, "Running discovery.");
        String[] services = basicQoSExample.runDiscovery();

        logger.log(Level.INFO, "Requesting offers");
            
        // creating descriptors

        RequestDescriptor reqDesc = basicQoSExample.createRequestDescriptor();

        QoSDescriptor qosDesc = basicQoSExample.createQoSDescriptor();
        
        // request offers

        OfferAndURI[] offers = basicQoSExample.requestOffers(services, reqDesc, qosDesc);
        
        logger.log(Level.INFO, "Confirming cheapest offers");
        OfferAndURI cheapest = basicQoSExample.getCheapest(offers);
        basicQoSExample.confirmOffer(cheapest);


        logger.log(Level.INFO, "Running job handling");
        basicQoSExample.runJobHandling(cheapest.getOffer().getSLAName().substring(8), cheapest.getURI());
    }     
   


   public RequestDescriptor createRequestDescriptor() {
    
        try {
            // create req desc for all services
    
            RequestDescriptor reqDesc = new RequestDescriptorImpl();
    
            reqDesc.setPerformanceParameter(reqDsc_perfParam1[0],reqDsc_perfParam1[1]);
    
            return reqDesc;

        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }
        return null;
    }

    public QoSDescriptor createQoSDescriptor() {

        try {
            QoSDescriptor qosDesc = new QoSDescriptorImpl();
    
            qosDesc.setConsumerName("Consumer: Mickey Mouse");
    
            qosDesc.setObjectivePrice(qosDsc_price);
            qosDesc.setObjectiveBeginTime(qosDsc_begin);
            qosDesc.setObjectiveEndTime(qosDsc_end); 
        
            return qosDesc;
            
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }
        return null;
    }

    public OfferAndURI[] requestOffers(String[] services, RequestDescriptor reqDesc, QoSDescriptor qosDesc) {
        
        
        Vector offers = new Vector();
        
        try {             
            // for all services:

            for (int count = 0; count < services.length; count++) {
                
                logger.log(Level.INFO, "Next service: " + services[count]);
                
                // init QoS Proxy with URI
                
                qosProxy.init(services[count]); 
                
                // request offer
                
                String qosDsc = qosProxy.requestQoSDescriptor(qosDesc.toString(),reqDesc.toString());
                
                if (qosDesc != null) {
    
                    // store offer and endpoint URI (wsdl URI)
    
                    QoSDescriptor offer = new QoSDescriptorImpl(qosDsc);

                    doLog(offer);             
    
                    OfferAndURI offerAndURI = new OfferAndURI(offer, services[count]);
                    
                    offers.add(offerAndURI);
                }
            }  
        } catch (eu.gemss.GridException ge) {
            logger.log(Level.SEVERE, "An error occured!", ge);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }
        
        // convert Vector (offers) to OfferAndURI array
        
        OfferAndURI[] offerAndURIs = new OfferAndURI[offers.size()];
        
        for (int count = 0; count < offerAndURIs.length; count++) {
        
            offerAndURIs[count] = (OfferAndURI)offers.get(count);
        }
        return offerAndURIs;

    }
        

    public OfferAndURI getCheapest(OfferAndURI[] offers) {
        
        OfferAndURI cheapest = null;

        try {
            
            // check cheapest offer
            
            for (int count = 0; count < offers.length; count++) {
                
                if ((cheapest == null) || (cheapest.getOffer().getObjectivePrice() > offers[count].getOffer().getObjectivePrice())) {
                    
                    cheapest = offers[count];
                }
            }   
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }
        return cheapest;
    }
 
    public void confirmOffer(OfferAndURI offerAndURI) {
        
        try {
        
            // confirm cheapest offer
            
            qosProxy.init(offerAndURI.getURI());
            qosProxy.confirmQoSDescriptor(offerAndURI.getOffer().toString());
            logger.log(Level.INFO,  "Negotiation result:\n" + 
                                    "Offer ID -> " + offerAndURI.getOffer().getSLAName() + "\n" +
                                    "Endpoint -> " + offerAndURI.getURI());
            
        } catch (Exception e) {
            logger.log(Level.SEVERE, "An error occured!", e);
        }
    }     




    private void doLog(Object o) {

        if (o instanceof QoSDescriptor) {
            QoSDescriptor offer = (QoSDescriptor) o;

            logger.log(Level.INFO,  "- Received offer:\n" +
                                    "  Begin time: " + formatCalendar(offer.getObjectiveBeginTime()) + "\n" +
                                    "  End time:   " + formatCalendar(offer.getObjectiveEndTime()) + "\n" +
                                    "  Price:      " + offer.getObjectivePrice());   
        } 
    }
 
    private String formatCalendar(Calendar calendar) {    
        SimpleDateFormat dateAndTimeFormatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss z"); 

        return (dateAndTimeFormatter.format(new Date(calendar.getTimeInMillis())));
    }


}

