<?php

namespace FCC;

class wallet {

    public static $WALLETEXISTS = null;
    public static $WALLETDIR = ".";
    
    public static $WXOR = [];

    public static function createtable() {
        $l = [];
        for ($c = 0; $c < 10; $c++) {
            array_push($l, ord($c));
        }
        for ($c = 'A'; $c <= 'F'; $c++) {
            array_push($l, ord($c));
        }
        foreach ($l as $m) {
            foreach ($l as $n) {
                self::$WXOR[] = ["add" => chr($m) . chr($n), "value" => $m ^ $n];
            }
        }
    }

    public static function findwallet() {
        if (!file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT)) {
            if (file_exists(self::$WALLETDIR . "/wallet/wallet" . \global::$FCCEXT)) {
                self::$WALLETDIR = self::$WALLETDIR . "/wallet";
            } elseif (is_dir(self::$WALLETDIR . "/wallet")) {
                self::$WALLETDIR = self::$WALLETDIR . "/wallet";
            } elseif (file_exists("../wallet" . \global::$FCCEXT)) {
                self::$WALLETDIR = "..";
            } elseif (file_exists("../wallet/wallet" . \global::$FCCEXT)) {
                self::$WALLETDIR = "../wallet";
            } elseif (is_dir("../wallet")) {
                self::$WALLETDIR = "../wallet";
            }
        }
        return file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT);
    }

    public static function publichash($wallet) {
        if (is_object($wallet) && get_class($wallet) === "FCC\\wallet") {
            $wallet = $wallet->wallet;
        }
        if (self::validwallet($wallet)) {
            return substr($wallet, 2, 64);
        }
        return "";
    }

    public static function validatehash($wid, $pubkey) {
        if (self::createwalletaddress($pubkey) === $wid) {
            return true;
        }
        return false;
    }

    public static function createwalletaddress($pubkey) {
        $pubhash = \global::securehash($pubkey);
        $xor = ord('5') ^ ord('1'); // 4
        if (\global::$COIN === 'PTTP') {
            $xor = ord('1') ^ ord('1');
        }
        for ($c = 0; $c < 64; $c++) {
            $xor ^= ord(substr($pubhash, $c, 1));
        }
        $checksum = "";
        foreach ($WXOR as $try) {
            if (($try["value"] ^ $xor) === 0) {
                $checksum = $try["add"];
                break;
            }
        }
        if (\global::$COIN === 'PTTP') {
            return '11' . $pubhash . $checksum;
        } else {
            return '51' . $pubhash . $checksum;
        }
    }

    public static function newwallet($name = null) {
        if (!$name) {
            $name = "[ No name ]";
        }
        $keypair = sodium_crypto_sign_keypair();
        $pubkey = sodium_crypto_sign_publickey($keypair);
        $privkey = sodium_crypto_sign_secretkey($keypair);

        $pubhex = \global::octhex($pubkey);
        $wallet = [
            "pubkey" => $pubhex,
            "privkey" => \global::octhex($privkey),
            "wallet" => self::createwalletaddress($pubhex),
            "name" => $name
        ];

        return $wallet;
    }

    public static function validwallet($wallet) {
        if (!$wallet) {
            return false;
        }
        $wallet = strtoupper($wallet);
        if (strlen($wallet) !== 68) {
            return false;
        }
        $xor = ord('5') ^ ord('1'); // 4
        if (\global::$COIN === 'PTTP') {
            $xor = ord('1') ^ ord('1');
            if (substr($wallet, 0, 2) !== '11') {
                return false;
            }
        } else {
            if (substr($wallet, 0, 2) !== '51') {
                return false;
            }
        }
        for ($c = 2; $c < 68; $c++) {
            $h = substr($wallet, $c, 1);
            if ((($h >= '0' && $h <= '9') || ($h >= 'A' && $h <= 'F'))) {
                $xor ^= ord($h);
            } else {
                return false;
            }
        }
        if ($xor !== 0) {
            return false;
        }
        return true;
    }

    public static function walletexists() {
        return file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT);
    }

    public static function walletisencoded() {
        if (file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT)) {
            $winfo = json_decode(gfio::content(self::$WALLETDIR . "/wallet" . \global::$FCCEXT), true);
            if (is_array($winfo) && isset($winfo["encoded"])) {
                if ($winfo["encoded"]) {
                    return true;
                }
            }
        }
        return false;
    }

    public static function loadwallets($password) {
        $wlist = [];
        echo "Looking for wallet at " . self::$WALLETDIR . "/wallet" . \global::$FCCEXT . "\n";
        if (file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT)) {
            $winfo = json_decode(gfio::content(self::$WALLETDIR . "/wallet" . \global::$FCCEXT), true);
            if (is_array($winfo)) {
                if (isset($winfo["encoded"])) {
                    if ($winfo["encoded"]) {
                        $seed = substr($winfo["encoded"], 0, 8);
                        $hash = substr($winfo["encoded"], 8);
                        $phash = \global::securehash($seed . \global::$COIN . $password);
                        if ($phash !== $hash) {
                            return [["error" => "invalid password"]];
                        }
                    }
                }
                $wlist = $winfo["wlist"];
                foreach ($wlist as &$wallet) {
                    if (!$wallet["name"]) {
                        $wallet["name"] = "[ No name ]";
                    }
                    if ($winfo["encoded"]) {
                        $wallet["pubkey"] = \global::fccencode(\global::hexoct($wallet["pubkey"]), $password);
                        $wallet["privkey"] = \global::fccencode(\global::hexoct($wallet["privkey"]), $password);
                    }
                }
            } else {
                foreach ($wlist as &$wallet) {
                    if (!$wallet["name"]) {
                        $wallet["name"] = "[ No name ]";
                    }
                }
                $wlist = $winfo;
            }
        }
        return $wlist;
    }

    public static function savewallet($wallet, $password) {
        if (!is_array($wallet) || !array_key_exists("wallet", $wallet)) {
            echo "FCC::wallet::savewallet - Wallet given is not a FCC blessed wallet\n";
            return;
        }
        $wlist = self::loadwallets($password);
        if (count($wlist) === 1 && isset($wlist[0]["error"])) {
            echo "FCC::wallet::savewallet - Adding wallet with wrong password\n";
            return;
        }
        array_push($wlist, $wallet);
        self::savewallets($wlist, $password);
    }

    public static function savewallets($wlist, $password) {
        // will overwrite password, be careful
        $enc = "";
        if ($password) {
            $seed = "";
            for ($i = 0; $i < 8; $i++) {
                $seed .= \global::hexchar(rand(0, 15));
            }
            $enc = $seed . \global::securehash($seed . \global::$COIN . $password);
        }
        $wcl = [];
        foreach ($wlist as $w) {
            $pub = $w["pubkey"];
            $priv = $w["privkey"];
            $name = $w["name"];
            if (!$w["name"]) {
                $name = "";
            }
            if ($password) {
                $pub = \global::fccencode(\global::hexoct($pub), $password);
                $priv = \global::fccencode(\global::hexoct($priv), $password);
            }
            $wcl[] = ["wallet" => $w["wallet"], "name" => $name, "pubkey" => $pub, "privkey" => $priv];
        }
        gfio::create(self::$WALLETDIR . "/wallet" . \global::$FCCEXT, json_encode_pretty(["encoded" => $enc, "version" => "2.1", "wlist" => $wcl]));
    }

    public static function loadwallet($wkey, $password) {
        if (isset($wkey)) {
            $wkey = strtoupper($wkey);
        }
        $wlist = self::loadwallets($password);
        if (count($wlist) === 1 && isset($wlist[0]["error"])) {
            return $wlist[0];
        }
        if (self::validwallet($wkey)) {
            foreach ($wlist as $wallet) {
                if ($wallet["wallet"] === $wkey) {
                    return $wallet;
                }
            }
        } elseif (!$wkey && count($wlist) >= 0) {
            return $wlist[0];
        }
        return null;
    }

    public static function validwalletpassword($password) {
        if (file_exists(self::$WALLETDIR . "/wallet" . \global::$FCCEXT)) {
            $winfo = json_decode(gfio::content(self::$WALLETDIR . "/wallet" . \global::$FCCEXT), true);
            if (is_array($winfo)) {
                if (isset($winfo["encoded"])) {
                    $seed = substr($winfo["encoded"], 0, 8);
                    $hash = substr($winfo["encoded"], 8);
                    $phash = \global::securehash($seed . global::$COIN . $password);
                    return ($phash === $hash);
                }
            }
        }
        return true;
    }
}
?>
