package com.k_int.ispp.deposit.soap;

import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import com.k_int.aggregator.core.*;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import java.util.Map;


@WebService(name = "ISPPPortType", targetNamespace = "http://dcsf.gov.uk/ISPP/Webservice")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public class ISPPDepositImpl implements ApplicationContextAware {
 
  private static Log log = LogFactory.getLog(ISPPDepositImpl.class);
  private ApplicationContext ctx = null;
  @Resource private WebServiceContext wsContext;



  public ISPPDepositImpl() {
    log.debug("New ISPPDepositImpl");
  }

  public void setApplicationContext(ApplicationContext ctx) {
    log.debug("Setting application context to "+ctx);
    this.ctx = ctx;
  }

  /**
   * Upload a document
   * 
   * @param doc
   * @return
   *     returns com.k_int.ispp.deposit.soap.UploadResponseT
   */
  @WebMethod
  @WebResult(name = "uploadResponse", targetNamespace = "http://dcsf.gov.uk/ISPP/Webservice/encodedTypes", partName = "result")
  public UploadResponseT upload(
        @WebParam(name = "uploadRequest", targetNamespace = "http://dcsf.gov.uk/ISPP/Webservice/encodedTypes", partName = "doc")
        UploadRequestT doc) {

    // https://jax-ws.dev.java.net/nonav/jax-ws-20-pfd/api/javax/xml/ws/handler/MessageContext.html
    // Provides some useful guidance on message context
    MessageContext msgContext = wsContext.getMessageContext();         
    Map requestHeaders = (Map) msgContext.get(MessageContext.HTTP_REQUEST_HEADERS) ;

    log.debug("request headers : "+requestHeaders);

    String user = (String) requestHeaders.get(BindingProvider.USERNAME_PROPERTY);
    String pass = (String) requestHeaders.get(BindingProvider.PASSWORD_PROPERTY);

    log.debug("Soap request headers for auth: "+user+"/"+pass);

    UploadResponseT result = new UploadResponseT();

    String owner = doc.owner;
    String upload_doc = doc.doc;
    String uploadContentType = "application/xml";
    Boolean authoritative = doc.authoritative;

    log.debug("upload "+upload_doc);
    log.debug("  owner:"+owner);
    log.debug("  contentType:"+uploadContentType);

    String depositor_id = "";
    AggregatorService aggregator = (AggregatorService) ctx.getBean("AggregatorService");

    int perms_validation = 0;

    IdentityService ident_service = (IdentityService) ctx.getBean("IdentityService");
    Map<String, AggregatorSourceHDO> valid_providers = getValidSourcesForDepositor(ident_service,user,sess);

    Map valid_provider_set = new HashMap<String, String>();
    if ( valid_providers != null ) {
      for (Entry<String, AggregatorSourceHDO> e : valid_providers.entrySet()) {
        valid_provider_set.put(e.getKey(), e.getKey()+" - "+e.getValue().getName());
      }
    }

    java.io.StringWriter addinfo_sw = new java.io.StringWriter();

    if ( valid_providers.keySet().contains(owner) ) {
      log.debug("calling aggregator core deposit method");
      DepositResult dr = aggregator.deposit(upload_doc.getBytes(), uploadContentType, user, owner, authoritative);
      if ( dr.getMessages() != null ) {
        for ( java.util.Iterator i = dr.getMessages().iterator(); i.hasNext(); ) {
          DepositMessage dm = (DepositMessage) i.next();
          addinfo_sw.write(""+dm.getCode()+":"+dm.getMessage()+"\n");
        }
      }
      result.setStatus(""+dr.getStatus());
      result.setLocation(""+dr.getDocId());
      result.setAddinfo(addinfo_sw.toString());
    }
    else {
      log.error("Permissions failure uploading to source "+owner+" by user "+user);
      result.setAddinfo("Permissions failure uploading to source "+owner+" by user "+user+" Your valid sources: "+valid_providers.keySet());
      result.setStatus(1);
    }

    return result;
  }

  public static Map<String, AggregatorSourceHDO> getValidSourcesForDepositor(IdentityService ident_service,
                                                                      String depositor_id,
                                                                      Session sess) {
    Map<String, AggregatorSourceHDO> sources = new HashMap<String, AggregatorSourceHDO>();

    try {
      TargetObjectIdentifier[] grants = ident_service.listGrantsFor(ident_service.usernameToId(depositor_id),
                                                                    "com.k_int.aggregator.perm.deposit");
      for (int i=0; i<grants.length; i++) {
        List<String> id_comps = grants[i].getIdentifierComponents();
        if (id_comps.size()>0) {
          Long src_id             = new Long(id_comps.get(0));
          AggregatorSourceHDO src = (AggregatorSourceHDO) sess.get(AggregatorSourceHDO.class,src_id);
          if (src!=null) {
            sources.put(src.getIdentifier(), src);
          }
        }
      }
    } catch (IdentityServiceException ise ) {
      log.warn("Problem listing data providers this user can upload on behalf of ", ise);
    }

    return sources;
  }

}
