/*
 *
 *  * Copyright 2014 http://Bither.net
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *    http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */

package net.bither.bitherj.core;

import net.bither.bitherj.crypto.ECKey;
import net.bither.bitherj.crypto.TransactionSignature;
import net.bither.bitherj.script.ScriptBuilder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Created by songchenwen on 15/6/3.
 */
public class EnterpriseHDMTxSignaturePool {
    private int threshold;
    private Tx tx;
    private List<byte[]> pubs;
    private byte[] multisigProgram;

    private HashMap<Integer, ArrayList<TransactionSignature>> signatures;

    public EnterpriseHDMTxSignaturePool(Tx tx, int threshold, List<byte[]> pubs) {
        assert !tx.isSigned();
        assert pubs.size() >= threshold;
        this.tx = tx;
        this.threshold = threshold;
        this.pubs = pubs;
        signatures = new HashMap<Integer, ArrayList<TransactionSignature>>();
        multisigProgram = ScriptBuilder.createMultiSigOutputScript(threshold, pubs).getProgram();
    }

    public boolean addSignature(List<byte[]> sigs) {
        if (sigs.size() != tx.getIns().size()) {
            return false;
        }
        ArrayList<TransactionSignature> txSigs = new ArrayList<TransactionSignature>();
        int pubIndex = -1;
        for (int i = 0;
             i < tx.getIns().size();
             i++) {
            TransactionSignature txSig = new TransactionSignature(ECKey.ECDSASignature
                    .decodeFromDER(sigs.get(i)), TransactionSignature.SigHash.ALL, false);
            if (i == 0) {
                byte[] pub = recoverPub(txSig, unsignedHashes().get(i));
            }
            txSigs.add(txSig);
        }

        return true;
    }

    public List<byte[]> unsignedHashes() {
        return tx.getUnsignedInHashesForHDM(multisigProgram);
    }

    public int signatureCount() {
        return signatures.values().size();
    }

    public int threshold() {
        return threshold;
    }

    private byte[] recoverPub(TransactionSignature signature, byte[] hash) {
        // TODO EnterpriseHDMTxSignaturePool recoverPub
        return null;
    }
}

@@ -2222,72 +2222,1296 @@
     
-%7D%0A            txSigs.add(txSig);%0A        %7D%0A%0A        return true;
+    if (pub == null) %7B%0A                    break;%0A                %7D%0A                pubIndex = pubs.indexOf(pub);%0A                if (pubIndex %3C 0) %7B%0A                    break;%0A                %7D%0A            %7D%0A            txSigs.add(txSig);%0A        %7D%0A        if (pubIndex %3C 0) %7B%0A            return false;%0A        %7D%0A        signatures.put(Integer.valueOf(pubIndex), txSigs);%0A        return true;%0A    %7D%0A%0A    public Tx sign() %7B%0A        assert satisfied();%0A        ArrayList%3Cbyte%5B%5D%3E txSigs = new ArrayList%3Cbyte%5B%5D%3E();%0A%0A        for (int inputIndex = 0;%0A             inputIndex %3C tx.getIns().size();%0A             inputIndex++) %7B%0A%0A            ArrayList%3CTransactionSignature%3E inputSigs = new ArrayList%3CTransactionSignature%3E();%0A%0A            for (Integer pubIndex = 0;%0A                 pubIndex %3C pubs.size();%0A                 pubIndex++) %7B%0A                if (signatures.containsKey(pubIndex)) %7B%0A                    inputSigs.add(signatures.get(pubIndex).get(inputIndex));%0A                %7D%0A            %7D%0A%0A            txSigs.add(ScriptBuilder.createP2SHMultiSigInputScript(inputSigs, multisigProgram)%0A                    .getProgram());%0A        %7D%0A%0A        tx.signWithSignatures(txSigs);%0A%0A        if (tx.verifySignatures()) %7B%0A            return tx;%0A        %7D else %7B%0A            return null;%0A        %7D
 %0A   
@@ -3618,32 +3618,120 @@
 rogram);%0A    %7D%0A%0A
+    public boolean satisfied() %7B%0A        return signatureCount() %3E= threshold();%0A    %7D%0A%0A
     public int s

Add Enterprise HDM Tx Signature Pool