/*
 *
 *  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.xrandom;

import net.bither.Bither;
import net.bither.bitherj.BitherjSettings;
import net.bither.bitherj.core.HDMKeychain;
import net.bither.bitherj.crypto.SecureCharSequence;
import net.bither.bitherj.delegate.HDMSingular;
import net.bither.preference.UserPreference;
import net.bither.utils.KeyUtil;
import net.bither.utils.LocaliserUtils;
import net.bither.utils.PeerUtil;
import net.bither.viewsystem.dialogs.MessageDialog;
import net.bither.viewsystem.froms.PasswordPanel;

import javax.swing.*;
import java.util.ArrayList;

public class HDMKeychainHotUEntropyDialog extends UEntropyDialog {

    public static HDMSingular hdmSingular;

    public HDMKeychainHotUEntropyDialog(PasswordPanel.PasswordGetter passwordGetter) {
        super(1, passwordGetter);
    }

    @Override
    void didSuccess(Object obj) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                quit();
                Bither.refreshFrame();
                if (UserPreference.getInstance().getAppMode() == BitherjSettings.AppMode.COLD) {
                    new MessageDialog(LocaliserUtils.getString("hdm_keychain_xrandom_final_confirm")).showMsg();
                }
            }
        });
    }

    @Override
    Thread getGeneratingThreadWithXRandom(UEntropyCollector collector) {
        return new GenerateThread(collector);
    }


    private class GenerateThread extends Thread {
        private double saveProgress = 0.1;
        private double startProgress = 0.01;
        private double progressKeyRate = 0.5;
        private double progressEntryptRate = 0.5;

        private long startGeneratingTime;

        private Runnable cancelRunnable;

        private UEntropyCollector entropyCollector;

        public GenerateThread(UEntropyCollector entropyCollector) {
            this.entropyCollector = entropyCollector;

        }

        @Override
        public synchronized void start() {
            super.start();
        }

        public void cancel(Runnable cancelRunnable) {
            this.cancelRunnable = cancelRunnable;
        }

        private void finishGenerate() {
            passwordGetter.wipe();
            PeerUtil.startPeer();
            entropyCollector.stop();
        }

        @Override
        public void run() {
            SecureCharSequence password = passwordGetter.getPassword();
            if (password == null) {
                throw new IllegalStateException("GenerateThread does not have password");
            }
            startGeneratingTime = System.currentTimeMillis();
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    onProgress(startProgress);
                }
            });
            boolean success = false;
            final ArrayList<String> addressStrs = new ArrayList<String>();
            double progress = startProgress;
            double itemProgress = (1.0 - startProgress - saveProgress) / (double) targetCount;
            try {
                entropyCollector.start();
                PeerUtil.stopPeer();
                for (int i = 0;
                     i < targetCount;
                     i++) {
                    if (cancelRunnable != null) {
                        finishGenerate();
                        SwingUtilities.invokeLater(cancelRunnable);
                        return;
                    }

                    XRandom xRandom = new XRandom(entropyCollector);

                    if (cancelRunnable != null) {
                        finishGenerate();
                        SwingUtilities.invokeLater(cancelRunnable);
                        return;
                    }


                    if (hdmSingular != null && hdmSingular.shouldGoSingularMode()) {
                        byte[] entropy = new byte[64];
                        xRandom.nextBytes(entropy);
                        progress += itemProgress * progressKeyRate;
                        onProgress(progress);
                        if (cancelRunnable != null) {
                            finishGenerate();
                            SwingUtilities.invokeLater(cancelRunnable);
                            return;
                        }
                        hdmSingular.setPassword(password);
                        hdmSingular.setEntropy(entropy);
                        hdmSingular.xrandomFinished();
                        progress += itemProgress * progressEntryptRate;
                        onProgress(progress);
                    } else {

                        HDMKeychain chain = new HDMKeychain(xRandom, passwordGetter.getPassword());

                        progress += itemProgress * progressKeyRate;
                        onProgress(progress);
                        if (cancelRunnable != null) {
                            finishGenerate();
                            SwingUtilities.invokeLater(cancelRunnable);
                            return;
                        }

                        KeyUtil.setHDKeyChain(chain);
                        progress += itemProgress * progressKeyRate;
                        onProgress(progress);
                    }
                    if (cancelRunnable != null) {
                        finishGenerate();
                        SwingUtilities.invokeLater(cancelRunnable);

                        return;
                    }
                    // start encrypt


                    progress += itemProgress * progressEntryptRate;
                    onProgress(progress);
                }
                entropyCollector.stop();
                passwordGetter.wipe();
                if (cancelRunnable != null) {
                    finishGenerate();
                    SwingUtilities.invokeLater(cancelRunnable);
                    return;
                }

                success = true;
            } catch (Exception e) {
                e.printStackTrace();
            }

            finishGenerate();
            if (success) {
                while (System.currentTimeMillis() - startGeneratingTime < MinGeneratingTime) {

                }
                onProgress(1);
                didSuccess(addressStrs);
            } else {
                onFailed();
            }
        }


        private void onFailed() {
            quit();
        }

    }

}