package service.handler.twostep;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.SignatureException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import message.Operation;
import message.twostep.csn.*;
import service.Config;
import service.handler.ConnectionHandler;
import utility.Utils;

/**
 *
 * @author Scott
 */
public class CSNHandler implements ConnectionHandler {
    public static final File ATTESTATION;
    
    private static final AtomicInteger CSN;
    private final Socket socket;
    private final KeyPair keyPair;
    
    static {
        ATTESTATION = new File("attestation/service-provider/csn");
        CSN = new AtomicInteger(0);
    }
    
    public CSNHandler(Socket socket, KeyPair keyPair) {
        this.socket = socket;
        this.keyPair = keyPair;
    }
    
    @Override
    public void run() {
        PublicKey clientPubKey = Utils.readKeyPair("client.key").getPublic();
        
        try (DataOutputStream out = new DataOutputStream(socket.getOutputStream());
             DataInputStream in = new DataInputStream(socket.getInputStream())) {
            Request req = Request.parse(Utils.receive(in));
            
            if (!req.validate(clientPubKey)) {
                throw new SignatureException("REQ validation failure");
            }
            
            String result;
            
            Operation op = req.getOperation();
            
            File file = new File(Config.DATA_DIR_PATH + '/' + op.getPath());
            boolean sendFileAfterAck = false;
            
            if (req.getConsecutiveSequenceNumber() == CSN.get() + 1) {
                CSN.incrementAndGet();
                
                String fname = Config.DATA_DIR_PATH + "/" + file.getName();
                
                switch (op.getType()) {
                    case UPLOAD:
                        Utils.receive(in, file);
                        
                        String digest = Utils.digest(file);
                        
                        if (op.getMessage().compareTo(digest) == 0) {
                            result = "ok";
                        } else {
                            result = "upload fail";
                        }
                        
                        Utils.writeDigest(file.getPath(), digest);
                        
                        break;
                    case AUDIT:
                        file = new File(op.getPath());
                        
                        result = Utils.readDigest(file.getPath());
                        
                        sendFileAfterAck = true;
                        
                        break;
                    case DOWNLOAD:
                        result = Utils.readDigest(file.getPath());
                        
                        sendFileAfterAck = true;
                        
                        break;
                    default:
                        result = "operation type mismatch";
                }
            } else {
                result = "CSN mismatch";
            }
            
            Acknowledgement ack = new Acknowledgement(result, req);
            
            ack.sign(keyPair);
            
            Utils.send(out, ack.toString());
            
            if (sendFileAfterAck) {
                Utils.send(out, file);
            }
            
            Utils.appendAndDigest(ATTESTATION, ack.toString() + '\n');
            
            socket.close();
        } catch (IOException | SignatureException ex) {
            Logger.getLogger(CSNHandler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

@@ -681,27 +681,11 @@
 tic 
-f
 in
-al AtomicInteger
+t
  CSN
@@ -858,28 +858,9 @@
 N = 
-new AtomicInteger(0)
+0
 ;%0A  
@@ -1804,14 +1804,8 @@
  CSN
-.get()
  + 1
@@ -1831,26 +1831,13 @@
  CSN
-.incrementAndGet()
+ += 1
 ;%0A  

optimize CSN handler