/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package de.christofreichardt.jaxws.securitypriceservice;

import de.christofreichardt.diagnosis.AbstractTracer;
import de.christofreichardt.diagnosis.LogLevel;
import de.christofreichardt.diagnosis.Traceable;
import de.christofreichardt.diagnosis.TracerFactory;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 *
 * @author Christof Reichardt
 */
@WebService(
    endpointInterface = "de.christofreichardt.jaxws.securitypriceservice.SecurityPriceServicePortType",
    serviceName = "SecurityPriceService")
@HandlerChain(file = "SecurityPriceService_handler.xml")
public class SecurityPriceServicePortTypeImpl implements SecurityPriceServicePortType, Traceable {
  final private Map<String, PriceExtractorStrategy> strategies = new HashMap<>();
  @Inject private TransactionIDMap transactionIDMap;

  public SecurityPriceServicePortTypeImpl() {
    this.strategies.put("OnVista", new OnVistaExtractor());
    this.strategies.put("Offline", new OfflineProvider());
  }
  
  @Override
  public SecurityPriceServiceResponse findPrice(SecurityPriceServiceRequest securityPriceServiceRequest) throws SecurityPriceServiceException {
    AbstractTracer tracer = getCurrentTracer();
    tracer.entry("SecurityPriceServiceResponseType", this, "findPrice(SecurityPriceServiceRequestType securityPriceServiceRequest)");
    
    try {
      tracer.out().printfIndentln("securityPriceServiceRequest.getProvider() = %s", securityPriceServiceRequest.getProvider());
      tracer.out().printfIndentln("securityPriceServiceRequest.getUserId() = %s", securityPriceServiceRequest.getUserId());
      tracer.out().printfIndentln("securityPriceServiceRequest.getTransactionId() = %s", securityPriceServiceRequest.getTransactionId());
      tracer.out().printfIndentln("isAllowed(%s, %d) = %s", 
          securityPriceServiceRequest.getUserId(), 
          securityPriceServiceRequest.getTransactionId(),
          this.transactionIDMap.isAllowed(securityPriceServiceRequest.getUserId(), securityPriceServiceRequest.getTransactionId())
      );
      
      if (!this.transactionIDMap.isAllowed(securityPriceServiceRequest.getUserId(), securityPriceServiceRequest.getTransactionId())) {
        SecurityPriceServiceFault securityPriceServiceFault = new SecurityPriceServiceFault();
        securityPriceServiceFault.setMessage("Illegal transactionId: " + securityPriceServiceRequest.getTransactionId() + ". Next valid Id: " + this.transactionIDMap.nextTransactionId(securityPriceServiceRequest.getUserId()));
        throw new MySecurityPriceServiceException(securityPriceServiceFault);
      }
      this.transactionIDMap.setTransactionId(securityPriceServiceRequest.getUserId(), securityPriceServiceRequest.getTransactionId());
      
      if (!this.strategies.containsKey(securityPriceServiceRequest.getProvider())) {
        SecurityPriceServiceFault securityPriceServiceFault = new SecurityPriceServiceFault();
        securityPriceServiceFault.setMessage("Unknown provider.");
        throw new MySecurityPriceServiceException(securityPriceServiceFault);
      }
      
      PriceExtractorStrategy provider = this.strategies.get(securityPriceServiceRequest.getProvider());
      ObjectFactory objectFactory = new ObjectFactory();
      SecurityPriceServiceResponse securityPriceServiceResponse = objectFactory.createSecurityPriceServiceResponse();
      List<AbstractSecurityPrice> securityPrices = securityPriceServiceResponse.getSharePriceOrIndexPriceOrOptionPrice();
      try {
        for (JAXBElement<String> id : securityPriceServiceRequest.getWKNOrISIN()) {
          tracer.out().printfIndentln("id.getValue() = %s", id.getValue());
          
          AbstractSecurityPrice securityPrice = null;
          securityPrice = provider.extractPrice(id.getValue());
          securityPrices.add(securityPrice);
        }
      }
      catch (NumberFormatException ex) {
        SecurityPriceServiceFault securityPriceServiceFault = new SecurityPriceServiceFault();
        securityPriceServiceFault.setMessage("Unexpected page layout");
        throw new MySecurityPriceServiceException(securityPriceServiceFault);
      }
      
      GregorianCalendar gregorianCalendar = new GregorianCalendar();
      try {
        DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
        XMLGregorianCalendar xmlGregorianCalendar = dataTypeFactory.newXMLGregorianCalendar(gregorianCalendar);
        securityPriceServiceResponse.setTimestamp(xmlGregorianCalendar);
      }
      catch (DatatypeConfigurationException ex) {
        tracer.logException(LogLevel.ERROR, ex, getClass(), "findPrice(SecurityPriceServiceRequestType securityPriceServiceRequest)");
      }

      return securityPriceServiceResponse;
    }
    finally {
      tracer.wayout();
    }
  }

  @Override
  public AbstractTracer getCurrentTracer() {
    return TracerFactory.getInstance().getCurrentQueueTracer();
  }

}
