/*
 * NIST HL7 Web Service
 * HL7MessageGeneration.java May 19,2008
 *
 * This code was produced by the National Institute of Standards and
 * Technology (NIST). See the "nist.disclaimer" file given in the distribution
 * for information on the use and redistribution of this software.
 */

package gov.nist.hl7.ws.messagegeneration;

import java.util.Map;
import javax.xml.transform.TransformerFactoryConfigurationError;
import gov.nist.hl7.core.message.AbstractMessage;
import gov.nist.hl7.core.message.XmlMessage;
import gov.nist.hl7.core.profile.Profile;

import gov.nist.hl7.core.generation.simple.SimpleMessageGenerationContextDocument; 
import gov.nist.hl7.core.validation.message.TableProfileDocument;
import gov.nist.hl7.ws.*;
import gov.nist.hl7.ws.messagegeneration.MessageGenerationUtils;

import org.apache.axis2.context.MessageContext;
import org.apache.log4j.Logger;


/**
 * @author Harold AFFO (NIST)
 */
public class HL7MessageGeneration implements HL7MessageGenerationInterface {

   protected Profile profile; 
   protected Profile clone;
   protected AbstractMessage message;
   protected String exception="";
   private MessageGenerationUtils mgUtils; 
   protected XmlMessage template; 
   protected SimpleMessageGenerationContextDocument smgContext = null; 
   protected TableProfileDocument resource=null; 
   private JdbcRepositoryDao rDao; 
   protected AbstractMessage resultats;

   private static Logger log=Logger.getLogger(HL7MessageGeneration.class);
   /**
    * Use the handle identified by the OID. A handle represents a package of
    * resources (e.g., a profile and a table file). The repository is searched
    * using the OID, if the handle is located all of the artifacts linked with
    * handle are used when performing message generation.
    * <p>
    * 
    * @param OID
    *            referencing a handle
    *            <p>
    * @return true if handle was located in the repository and processed
    *         successfully; false otherwise.
    * @throws Exception
    */
   public boolean useHandle(String OID) throws Exception {
      try { 
         Map<String, Object> map = mgUtils.useHandle(OID, rDao);
         resource = (TableProfileDocument) map.get("resource");
         profile = (Profile) map.get("profile");
         log.info("User uses the handle with OID : " + OID);
      } catch (Exception e) {
         exception += e + "\n";
         log.error(e);
         throw e;
      } 
      return true;
   }

   /**
    * Load an HL7 version 2 message profile. The profile is an XML document
    * that follows the rules given in the HL7 version 2 profile schema.
    * <p>
    * 
    * @param xmlProfile an HL7 version 2 message profile.
    *            <p>
    * @return true if profile was loaded and processed successfully; false
    *         otherwise.
    * @throws Exception
    */
   public boolean loadProfile(String xmlProfile) throws Exception {
      try{
         profile = mgUtils.getProfile(xmlProfile);
         log.info("User loads profile");
      }catch (Exception e) {
         exception += e + "\n";
         log.fatal(e);
         throw e;
      }  
      return true;
   }


   /**
    * Use the profile identified by the OID. The repository is searched using
    * the OID, if the profile is located it is use for performing message
    * generation.
    * <p>
    * 
    * @param OID referencing an HL7 version message profile.
    *            <p>
    * @return true if profile was located in the repository and processed
    *         successfully; false otherwise.
    * @throws Exception
    */
   public boolean useProfile(String OID) throws Exception {
      //begin testing
      String sessionId = (String) MessageContext.getCurrentMessageContext().getOptions().getProperty("SessionId");
      log.info("useProfile:The sessin id is "+sessionId);
      log.info("The context is "+MessageContext.getCurrentMessageContext().getServiceGroupContextId());
      //end testing
      try {
         profile=null ; 
         profile=(Profile)rDao.getProfile(OID); 
         log.info("User uses the profile with OID :"+OID );
         log.info(profile.getMessageStructureID());
      } catch (Exception e) {
         exception += e + "\n";
         log.fatal(e);
         throw e;
      }  
      return true;
   }


   /**
    * The loadResource method allows a user to load additional resources that
    * can be used in the generation process. This may be a table that specifies
    * local codes. Each resource type defines the format of the given resource.
    * More than one resource can be associated to a generation process.
    * <p>
    * TBD-what are the resource types and their formats.
    * <p>
    * 
    * @param xmlResource
    *            a resource that is used in the generation process.
    *            <p>
    * @param resourceType
    *            a document that describes the type of the xmlResource; for
    *            example, an XML schema.
    *            <p>
    * @return true if the resource has been successfully loaded and processed;
    *         false otherwise.
    * @throws Exception
    */
   public boolean loadResource(java.lang.String xmlResource,
         java.lang.String resourceType) throws Exception {
      try {
         resource=TableProfileDocument.Factory.parse(xmlResource);
         log.info("User loads resource");
      } catch (Exception e) { 
         exception += e + "\n";
         log.fatal(e);
         throw e;
      }
      return true;
   }

   /**
    * The useResource method allows a user to access a resource that can be
    * used in the generation process. This may be a table that specifies local
    * codes. More than one resource can be associated to a generation process.
    * Resource files are stored in the repository.
    * <p>
    * TBD-what are the resource types and their formats.
    * <p>
    * 
    * @param OID
    *            an object identifier to reference the resource
    *            <p>
    * @return true if the resource was located in the repository and processed
    *         successfully; false otherwise.
    * @throws Exception
    */
   public boolean useResource(java.lang.String OID) throws Exception {
      try {
         resource = rDao.getResource(OID);
         log.info("User uses the resource with OID :"+OID);
      } catch (Exception e) {
         exception += e + "\n";
         log.fatal(e);
         throw e;
      } 
      return true ; 	 
   }

   /**
    * The generation context describes the location and values used for
    * creating messages. The generation context is encoded in an XML document
    * that adheres to the generation context schema. For details of the format
    * see...
    * <p>
    * 
    * @param simpleGenerationContext
    *            the message generation context describes the location and
    *            values used for creating messages.
    *            <p>
    * @return true is the validation context has been successfully loaded and
    *         processed; false otherwise.
    * @throws Exception
    */
   public boolean setGenerationContext(java.lang.String simpleGenerationContext)
   throws Exception {
      //begin testing
      String serviceGroupID=MessageContext.getCurrentMessageContext().getServiceGroupContextId();
      String sessionId = (String) MessageContext.getCurrentMessageContext().getOptions().getProperty("SessionId");
      log.info("setGenerationContext: The sessin id is "+sessionId);
      log.info("The context is "+serviceGroupID);
      //end testing
      try {
         smgContext=mgUtils.getSimpleMessageGenerationContext(simpleGenerationContext);	
      } catch (Exception e) {
         exception += e + "\n";
         log.fatal(e);
         throw e;
      } 
      return true;
   } 


   /**
    * Perform the message generation.
    * <p>
    * 
    * @return true if the message was successfully generated; false otherwise.
    * @throws Exception
    * @throws TransformerFactoryConfigurationError
    * @throws Exception
    */

   public boolean generate() throws Exception {
      //begin testing
      /**String sessionId = (String) MessageContext.getCurrentMessageContext().getOptions().getProperty("SessionId");
      log.info("generate:The sessin id is"+sessionId);
      log.info("The context is "+MessageContext.getCurrentMessageContext().getServiceGroupContextId());*/
      log.info("The profile structure is");
      if(profile!=null)
         log.info(profile.getMessageStructureID());
      else
         log.info("profile was null");

      //end testing
      if(mgUtils!=null)
         log.info("mgUtils"+mgUtils.toString());
      else
         log.info("mgUtils was null");
      try {
         resultats=mgUtils.generate(profile,smgContext,resource);  
         mgUtils.clear(profile ,message, smgContext, exception,resource); 
      } catch (Exception e) {
         exception += e + "\n";
         log.fatal(e);
         throw e;
      }   
      log.info("generate:"+resultats);
      return true;
   }

   /**
    * Get the status of the service.
    * <p>
    * 
    * @return true if the service is available; false if the service
    *         unavailable (e.g., running but too busy).
    */
   public  boolean getServiceStatus(){
      boolean ret=false;
      return ret;
   }

   /**
    * Retrieve the message as a string .
    * <p>
    * 
    * @return an XML or ER7 document with a detailed of the message generation
    *         results.
    * @throws Exception 
    * 
    */
   public String getMessage() throws Exception{
      String message=null;
      try{
         message = mgUtils.getMessage(resultats);
         resultats = null;
      }catch (Exception e){
         exception += e + "\n";
         log.fatal(e);
         throw e; 
      }
      return message;  
   }

   /**
    * Implemented to test Stateless implementation
    * 
    * @param OID
    * @param simpleGenerationContext
    * @return
    * @throws Exception
    */
   public String statelessCall(String OID,java.lang.String simpleGenerationContext) throws Exception{
      setGenerationContext(simpleGenerationContext);
      useProfile(OID);
      generate();
      return getMessage();
   }

   /**
    * Get the web service error message of the last exception caught.
    * <p>
    * 
    * @return a description of the last exception.
    */
   public String getLastExceptionMessage(){
      String lastException = exception;
      log.info("User gets the last exception message");
      return lastException;
   }

   public void setMessageGenerationUtils(MessageGenerationUtils mgUtils) {
      this.mgUtils=mgUtils;
   }

   public void setJdbcRepositoryDao(JdbcRepositoryDao inRDao) {
      this.rDao=inRDao;
   }

   public java.lang.String getNewSession() throws Exception
   {

      log.info(MessageContext.getCurrentMessageContext().getServiceGroupContextId());
      return MessageContext.getCurrentMessageContext().getServiceGroupContextId();

   }
}
