package won.protocol.message.processor.impl;

import org.apache.jena.query.Dataset;
import org.apache.jena.rdf.model.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
import won.cryptography.keymanagement.KeyPairAliasDerivationStrategy;
import won.cryptography.rdfsign.WonKeysReaderWriter;
import won.cryptography.service.CryptographyService;
import won.protocol.message.WonMessage;
import won.protocol.message.WonMessageEncoder;
import won.protocol.message.WonMessageType;
import won.protocol.message.processor.WonMessageProcessor;
import won.protocol.message.processor.exception.WonMessageProcessingException;

import java.security.PublicKey;

/**
 *  This processor is intended for use in owners (bot or webapp).
 *
 *  If the message type is CREATE, the processor adds the appropriate public key to the need's RDF content.
 *
 *  If the <code>fixedPrivateKeyAlias</code> property is set, the processor generates at most one key pair with that alias
 *  and uses that key pair for all need it processes.
 *
 *  If the <code>fixedPrivateKeyAlias</code> property is not set, the processor generates one keypair per need, using
 *  the need URI as the keypair's alias.
 *
 *  This processor should be removed when user's/need's key management and signing happens in
 *  the Owner Client (browser).
 *
 * User: ypanchenko
 * Date: 10.04.2015
 */
public class KeyForNewNeedAddingProcessor implements WonMessageProcessor {
  private static final Logger logger = LoggerFactory.getLogger(KeyForNewNeedAddingProcessor.class);

  private CryptographyService cryptographyService;
  ThreadLocal<StopWatch> stopWatchThreadLocal = new ThreadLocal<>();

  private KeyPairAliasDerivationStrategy keyPairAliasDerivationStrategy;

  public KeyForNewNeedAddingProcessor() {
  }

  public void setCryptographyService(final CryptographyService cryptoService) {
    this.cryptographyService = cryptoService;
  }

  @Override
  public WonMessage process(final WonMessage message) throws WonMessageProcessingException {
    StopWatch stopWatch = getStopWatch();
    try {
      if (message.getMessageType() == WonMessageType.CREATE_NEED) {
        String needUri = message.getSenderNeedURI().toString();
        Dataset msgDataset =  WonMessageEncoder.encodeAsDataset(message);
        // generate and add need's public key to the need content

        if (logger.isDebugEnabled()){
          stopWatch.start();
        }
        String alias = keyPairAliasDerivationStrategy.getAliasForNeedUri(needUri);
        if (cryptographyService.getPrivateKey(alias) == null) {
          cryptographyService.createNewKeyPair(alias, alias);
        }

        if (logger.isDebugEnabled()) {
          stopWatchStopAndLog(stopWatch);
        }
        PublicKey pubKey = cryptographyService.getPublicKey(alias);
        WonKeysReaderWriter keyWriter = new WonKeysReaderWriter();
        String contentName = message.getContentGraphURIs().get(0);
        Model contentModel = msgDataset.getNamedModel(contentName);
        keyWriter.writeToModel(contentModel, contentModel.createResource(needUri), pubKey);
        return new WonMessage(msgDataset);
      }
    } catch (Exception e) {
      logger.error("Failed to add key", e);
      throw new WonMessageProcessingException("Failed to add key for need in message " + message.getMessageURI().toString());
    }
    return message;
  }

  public void setKeyPairAliasDerivationStrategy(KeyPairAliasDerivationStrategy keyPairAliasDerivationStrategy) {
    this.keyPairAliasDerivationStrategy = keyPairAliasDerivationStrategy;
  }

  private void stopWatchStopAndLog(StopWatch stopWatch) {
    stopWatch.stop();
    if (stopWatch.getTaskCount() % 10 == 0) {
      logger
              .debug("creating keypair takes {} millis on average", String.format("%.2f", ((double) stopWatch
                      .getTotalTimeMillis() / stopWatch
                      .getTaskCount())));
    }
  }

  private StopWatch getStopWatch() {
    StopWatch stopWatch = stopWatchThreadLocal.get();
    if (stopWatch == null) {
      stopWatch = new StopWatch();
      stopWatchThreadLocal.set(stopWatch);
    }
    return stopWatch;
  }
}

@@ -1625,77 +1625,8 @@
 ice;
-%0A  ThreadLocal%3CStopWatch%3E stopWatchThreadLocal = new ThreadLocal%3C%3E();
 %0A%0A  
@@ -1984,50 +1984,8 @@
 n %7B%0A
-    StopWatch stopWatch = getStopWatch();%0A
     
@@ -2267,85 +2267,8 @@
 nt%0A%0A
-        if (logger.isDebugEnabled())%7B%0A          stopWatch.start();%0A        %7D%0A
     
@@ -2487,99 +2487,8 @@
  %7D%0A%0A
-        if (logger.isDebugEnabled()) %7B%0A          stopWatchStopAndLog(stopWatch);%0A        %7D%0A
     
@@ -3321,594 +3321,6 @@
  %7D%0A%0A
-  private void stopWatchStopAndLog(StopWatch stopWatch) %7B%0A    stopWatch.stop();%0A    if (stopWatch.getTaskCount() %25 10 == 0) %7B%0A      logger%0A              .debug(%22creating keypair takes %7B%7D millis on average%22, String.format(%22%25.2f%22, ((double) stopWatch%0A                      .getTotalTimeMillis() / stopWatch%0A                      .getTaskCount())));%0A    %7D%0A  %7D%0A%0A  private StopWatch getStopWatch() %7B%0A    StopWatch stopWatch = stopWatchThreadLocal.get();%0A    if (stopWatch == null) %7B%0A      stopWatch = new StopWatch();%0A      stopWatchThreadLocal.set(stopWatch);%0A    %7D%0A    return stopWatch;%0A  %7D%0A
 %7D%0A

Remove timing code