<?php
defined('BASEPATH') or exit('No direct script access allowed');
define('PATH_CODEGEN', "/usr/local/sbin/codegen");

class Order
{
    private $generatePrevProgram;

    private $orderData;
    private $ctrID;
    private $userID;

    private $db;
    private $error;

    private $partnerEmail;
    private $partnerSubEmail;

    private $product;
    private $finalPrice;
    private $credit;
    private $orderNumber;
    private $version;
    private $liveVersion;

    private $serial;
    private $liveSerial;
    private $prevSerials;
    private $expirationDate = '2050-01-01';
    private $customExpDate = '';
    private $programGenerated = 1;
    private $serialArray = array();
    private $needDate = false;

    private $module;

    function __construct($orderData, $ctrID)
    {
        $this->db           = &get_instance();
        $this->orderData    = $orderData;
        $this->ctrID        = $ctrID;

        $this->db->load->library('PasswordHash');
        $this->db->load->library('Product');
        $this->db->load->helper('email');
        $this->db->load->library('SzamlaAgent');

        $this->generatePrevProgram  = Product::$generatePrevProgram;
        $customPrice                = isset($orderData->customPrice) ? $orderData->customPrice : '';

        if ($ctrID == '43') {
            $this->generatePrevProgram = false;
        }

        $this->setProduct($orderData->customPrice);
        $this->setOrderNumber();
        $this->setPartnerEmail();
        $this->setVersions();
    }

    private function setProduct($customPrice = '')
    {
        $product = $this->db->db->query("SELECT * FROM cl_hlusers.o_products WHERE id = " . (int)$this->orderData->product_id . " AND lang = '{$this->ctrID}'")->row();

        if ($product->akcio != '' && $product->akcio != null && date('Y-m-d') <= $product->ackio_date) {
            $product->price = $product->akcio;
        } else {
            if (substr($this->ctrID, 0, 2) == '11')
                $product->price = $product->usd;
            else
                $product->price = $product->euro;
        }

        $product->price = $product->incl_live == 1 ? $this->getBundlePrice() : $product->price;

        $this->finalPrice = $product->incl_live == 1 ? $this->getBundlePrice() : $product->price;

        if ($customPrice != '') {
            $product->price = $customPrice;
            $this->finalPrice = $customPrice;
        }
        $this->product = $product;
    }

    private function setVersions()
    {
        if ($this->product->kategoria == 'nonp') {
            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 24")->row();
        } else {
            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 25")->row();
        }

        if ($this->product->id == 2036 || $this->product->id == 2037) {
            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 23")->row();
        }

        if ($this->product->id == 2112) {
            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 20")->row();
        }

        if ($this->ctrID == '43') {
            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 24")->row();
        }

        $liveVersion = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = 23")->row();

        $this->version = $version;
        $this->liveVersion = $liveVersion;
    }

    private function canOrder()
    {
        if ($this->ctrID == '' || $this->ctrID == null) {
            $this->error = "Your session is expired. Please login.";
            return false;
        }

        if ($this->partnerEmail == '') {
            $this->error = "Access denied.";
            return false;
        }

        $limit      = $this->getUserLimit();
        $maxLimit   = $this->product->limit;

        if ($limit >= $maxLimit) {
            $this->error = "You've reached your daily limit for orders. Please try it again tomorrow or contact <a href='mailto:office@cadline.hu'>office@cadline.hu</a>.";
            return false;
        }

        return true;
    }

    private function getDistributor()
    {
        $distID = 0;

        $distributor = $this->db->db->query("SELECT id FROM cl_hlusers.distributors WHERE ctrID = '{$this->ctrID}'")->row();

        if (!empty($distributor))
            $distID = $distributor->id;

        return $distID;
    }

    private function setOrderNumber()
    {
        $lastOrder      = $this->db->db->query("SELECT o.order FROM cl_hlusers.o_orders o WHERE o.country = " . (int)$this->ctrID . " ORDER BY o.id DESC LIMIT 1")->row();
        $orderNumber    = $lastOrder->order;
        $first          = strpos($orderNumber, "-") + 1;
        $last           = strpos($orderNumber, "/") - 2;
        $number         = (int)substr($orderNumber, $first, $last) + 1;

        $this->orderNumber = "E-" . $number . "/" . date("Y");
    }

    private function phoneCorrect($phoneNumber)
    {
        $phone = $phoneNumber;
        $phone = str_replace('-', '', $phone);
        $phone = str_replace(' ', '', $phone);
        $phone = str_replace('+', '', $phone);
        $phone = str_replace('/', '', $phone);
        $phone = str_replace('.', '', $phone);
        $phone = str_replace('  ', '', $phone);

        return $phone;
    }

    private function setUserID()
    {
        $retrievedUser = $this->db->db->query("SELECT nUserID FROM cl_hlusers.u_emails WHERE email = '{$this->orderData->email}'")->row();

        if (empty($retrievedUser)) {
            $this->userID = $this->insertUser();
        } else {
            $this->userID = (int)$retrievedUser->nUserID;
        }
    }

    private function insertUser()
    {
        $distID = $this->getDistributor();

        if ($this->product->kategoria == 'nonp') {
            $status     = '4';
            $userType   = 2;
        } else {
            $status     = '11';
            $userType   = 1;
        }

        $user               = new stdClass();
        $user->strName      = $this->orderData->name;
        $user->nManagerID   = 36;
        $user->nSchoolID    = 0;
        $user->deleted      = 0;
        $user->old_db       = 'clusers_eng';
        $user->bNewsletter  = 'N';
        $user->strEMail     = $this->orderData->email;
        $user->strCurrency  = substr($this->ctrID, 0, 2) == '11' ? 'USD' : 'EUR';
        $user->nCtrID       = substr($this->ctrID, 0, 2);
        $user->nUserStatus  = $status;
        $user->nDistID      = $distID;
        $user->nUserType    = $userType;

        $this->db->db->insert("cl_hlusers.users", $user);
        $nUserID = $this->db->db->insert_id();

        $exploded_email = explode("@", $this->orderData->email);

        $phpass = new PasswordHash(10, true);
        $password = $phpass->HashPassword($exploded_email[0]);

        $jmlUser                = new stdClass();
        $jmlUser->name          = $this->orderData->name;
        $jmlUser->username      = $this->orderData->email;
        $jmlUser->email         = $this->orderData->email;
        $jmlUser->password      = $password;
        $jmlUser->registerDate  = date('Y-m-d');
        $jmlUser->nUserID       = $nUserID;

        $this->db->db->insert("www_archline_hu.jml_users", $jmlUser);
        $jmlID = $this->db->db->insert_id();

        $jmlGroup           = new stdClass();
        $jmlGroup->user_id  = $jmlID;
        $jmlGroup->group_id = 2;

        $this->db->db->insert("www_archline_hu.jml_user_usergroup_map", $jmlGroup);

        $history                = new stdClass();
        $history->nUserID       = $nUserID;
        $history->nTopicID      = 382;
        $history->dateEvent     = date('Y-m-d');
        $history->strPlace      = 'Weborder';
        $history->strInfo       = 'Weborderen regisztrált';
        $history->nManagerID    = 36;
        $history->insertDate    = date('Y-m-d H:i:s');

        $this->db->db->insert("cl_hlusers.u_history", $history);

        $u_email                = new stdClass();
        $u_email->email         = $this->orderData->email;
        $u_email->nUserID       = $nUserID;
        $u_email->default       = 1;
        $u_email->active        = 1;
        $u_email->deleted       = 0;
        $u_email->newsletter    = 1;

        $this->db->db->insert("cl_hlusers.u_emails", $u_email);

        return $nUserID;
    }

    private function getUserLimit()
    {
        $ip     = $_SERVER['REMOTE_ADDR'];
        $limit  = $this->db->db->query("SELECT ip, COUNT(ip) as szam FROM cl_hlusers.o_orders WHERE ip = '" . $ip . "' AND DATE = CURDATE()")->row();

        return $limit->szam;
    }

    private function setPartnerEmail()
    {
        $emails = $this->db->db->query("SELECT DISTINCT email, sub_email FROM cl_hlusers.o_products WHERE lang = '{$this->ctrID}'")->row();

        $this->partnerEmail     = $emails->email;
        $this->partnerSubEmail  = $emails->sub_email;
    }

    private function createOrder()
    {
        $ip = $_SERVER['REMOTE_ADDR'];

        $instalments = $this->getInstalments();

        $order              = new stdClass();
        $order->ip          = $ip;
        $order->country     = $this->ctrID;
        $order->date        = date('Y-m-d');
        $order->software    = $this->product->termek;
        $order->user_name   = $this->orderData->name;
        $order->user_email  = $this->orderData->email;
        $order->order       = $this->orderNumber;
        $order->input_key   = $this->orderData->old_hl_number;
        $order->output_key  = $this->serial;
        $order->price       = $this->finalPrice;
        $order->info        = $this->orderData->info;
        $order->instalments = $instalments['payment'];
        $order->live_key    = $this->liveSerial;

        $this->db->db->insert("cl_hlusers.o_orders", $order);
    }

    private function getInstalments()
    {
        $result                 = array();
        $today                  = date("Y-m-d");
        $result['reszlet']      = '';
        $result['payment']      = 'pay in full';
        $result['fizHatIdo']    = '';
        $result['period']       = 0;

        if ($this->product->kategoria == 'perp') {
            if ($this->orderData->inst_pay == 'on') {
                switch ($this->ctrID) {
                    case '43':
                        if (strstr($this->product->termek, "Professional") || strstr($this->product->termek, "Prof.")) {
                            $result['payment']  = 'Instalments: 3 Period: monthly';
                            $result['period']   = 3;
                        }

                        if ($this->orderData->product_id == '191') {
                            $result['payment']  = 'Instalments: 3 Period: monthly';
                            $result['period']   = 3;
                        }
                        break;

                    case '380':
                        $result['payment']  = 'Instalments: 3 Period: monthly';
                        $result['period']   = 3;
                        break;

                        /*case '44':
                        if (strstr($this->product->termek, "Professional") || strstr($this->product->termek, "Prof.")) {
                            $result['payment'] = 'Instalments: 4  Period: monthly';
                        }
                        break;*/

                    case '39':
                        $result['reszlet']      = "12";
                        $result['payment']      = 'Instalments: 2 Period: yearly';
                        $result['fizHatIdo']    = date('Y-m', strtotime($today . '+365 days'));
                        $result['period']       = 2;
                        break;

                    case '37':
                        $result['payment']  = 'Instalments: 3 Period: monthly';
                        $result['period']   = 3;

                    default:
                        break;
                }
            } else {
                $result['reszlet']      = "";
                $result['payment']      = 'pay in full';
                $result['fizHatIdo']    = date('Y-m', strtotime($today . '+365 days'));
            }
        }

        return $result;
    }

    private function getVersionFromVercode($verCode)
    {
        return $this->db->db->query("SELECT * FROM cl_hlusers.p_versions v WHERE v.verCode = {$verCode} LIMIT 1")->row();
    }

    private function setPassword($key, $verCode, $type, $lan = 0)
    {
        $command        = PATH_CODEGEN . " -Password " . $key . $verCode . $lan . $type;
        $ph             = popen($command, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
        $this->serial   = fgets($ph, 1024);
        pclose($ph);
    }

    private function setLivePassword($key)
    {
        $lan    = 0;
        $type   = "L";

        $command            = PATH_CODEGEN . " -Password " . $key . $this->liveVersion->verCode . $lan . $type;
        $ph                 = popen($command, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
        $this->liveSerial   = fgets($ph, 1024);
        pclose($ph);
    }

    private function setPreviousPasswords($key)
    {
        $lan = 0;
        $prevs = (array)$this->orderData->prev_softwares;

        for ($i = 0; $i < count($prevs); $i++) {
            $command    = PATH_CODEGEN . " -Password " . $key . $prevs[$i] . $lan . $this->product->type;
            $ph         = popen($command, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
            $password   = fgets($ph, 1024);
            pclose($ph);

            $version = $this->getVersionFromVercode($prevs[$i]);

            $this->prevSerials[$password]->year     = $version->year;
            $this->prevSerials[$password]->verID    = $version->verID;
        }
    }

    private function getSoftwareKey()
    {
        $key = $this->db->db->query("SELECT hlNum FROM cl_hlusers.hardlock WHERE hlNum LIKE '95%' ORDER BY hlNum DESC LIMIT 1")->row();

        return $key->hlNum + 1;
    }

    private function createHardlockKey($ctrKey)
    {
        $compLt = $this->product->kategoria == 'comp' && $this->product->type == '4';
        if ($ctrKey || $this->product->kategoria == 'live' || $this->product->kategoria == 'lt' || $compLt || $this->product->type == 'L') {
            $key = $this->db->db->query("SELECT hlNum FROM cl_hlusers.hardlock WHERE hlNum LIKE '{$this->ctrID}%' ORDER BY hlNum DESC LIMIT 1")->row();

            if (empty($key))
                $key = ($this->ctrID * 10000) + 1;
            else
                $key = $key->hlNum + 1;
        }

        $compProf = $this->product->kategoria == 'comp' && $this->product->type == '8';
        if (($this->product->kategoria == 'perp' || $compProf || $this->product->kategoria == 'crossgrade' || $this->product->kategoria == 'subscription') && !$ctrKey) {
            if ($this->orderData->hl_prot == 'on')
                $key = $this->orderData->hl_select;
            else
                $key = $this->getSoftwareKey();
        }

        if ($this->product->kategoria == 'nonp') {
            $key = $this->db->db->query("SELECT hlNum FROM cl_hlusers.hardlock WHERE hlNum LIKE '99%' AND hlStat = 0 AND hlLan = 0 ORDER BY hlNum DESC LIMIT 1")->row();
            $key = $key->hlNum;
        }

        return $key;
    }

    private function getBundlePrice()
    {
        $bundlePrice = 0;

        $query = "SELECT euro, usd
            FROM cl_hlusers.o_products
            WHERE lang = '{$this->ctrID}' AND seq = 2 LIMIT 2";
        $products = $this->db->db->query($query)->result();

        foreach ($products as $product) {
            $bundlePrice += substr($this->ctrID, 0, 2) == '11' ? $product->usd : $product->euro;
        }

        $discount = 0.15 * $bundlePrice;
        $finalBundlePrice = $bundlePrice - $discount;

        return $finalBundlePrice;
    }

    private function updateFinalPrice()
    {
        if ($this->product->kategoria == 'subscription' && strpos($this->product->termek, "monthly"))
            $this->finalPrice *= 3;

        if (count($this->orderData->prev_softwares) > 0 && $this->generatePrevProgram == false)
            $this->finalPrice += Product::getPrevSoftwarePrice($this->ctrID);

        if ($this->orderData->inclLive == 'on' && $this->product->kategoria != 'nonp')
            $this->finalPrice += Product::getLivePrice($this->ctrID);

        if ($this->orderData->hl_prot == 'on')
            $this->finalPrice += Product::getHardlockPrice($this->ctrID);

        if ($this->orderData->module != '') {
            $modulePrice = $this->getModulePrice($this->orderData->module);

            if ($this->product->kategoria == 'subscription' && strpos($this->product->termek, "monthly"))
                $this->finalPrice += $modulePrice * 3;
            else
                $this->finalPrice += $this->getModulePrice($this->orderData->module);
        }

        if ($this->orderData->floating_lic == 'on')
            $this->finalPrice += Product::getFloatingPrice($this->ctrID);

        if ($this->orderData->lan_quantity && $this->orderData->lan_quantity > 1) {
            $lanPrice = $this->product->kategoria == 'lan' ? $this->product->price : Product::getLanPrice($this->ctrID, $this->product->type);
            $this->finalPrice += ($this->orderData->lan_quantity - 1) * $lanPrice;
        }

        if ($this->orderData->credit == 'on') {
            if ($this->finalPrice > $this->product->credit)
                $this->credit = $this->product->credit;
            else
                $this->credit = $this->finalPrice;

            $this->finalPrice -= $this->credit;
        }
    }

    private function updateCredit()
    {
        (int)$deducted_credit = $this->product->credit - $this->credit;

        $updateQuery = "UPDATE cl_hlusers.o_products
                SET credit = {$deducted_credit}
                WHERE lang = '{$this->ctrID}'";

        $this->db->db->query($updateQuery);
    }

    private function keyExist($key)
    {
        $exist = $this->db->db->query("SELECT hlNum FROM cl_hlusers.hardlock WHERE hlNum = '{$key}' LIMIT 1")->row();

        return !empty($exist);
    }

    private function createHardlock($key, $isLive, $lan = 0, $floating = 0)
    {
        $hardlock               = new stdClass();
        $hardlock->hlNum        = $key;
        $hardlock->hlLan        = $lan;
        $hardlock->hlStat       = 1;
        $hardlock->hlDateIssue  = date('Y-m-d');
        $hardlock->hlUser       = $this->userID;
        $hardlock->hlManID      = 36;
        $hardlock->hlCtrID      = $this->ctrID;
        $hardlock->old_db       = 'clusers_eng';
        $hardlock->hlTime       = date("Y-m-d H:i:s");
        $hardlock->product_id   = $isLive ? 2 : Product::getProductID($this->product->kategoria);
        $hardlock->isFloating   = $floating;

        $this->db->db->insert("cl_hlusers.hardlock", $hardlock);
    }

    private function updateHardlock($key, $isLive, $lan = 0, $floating = 0)
    {
        $key = substr($key, 0, 6);

        $hlDateIssue  = date('Y-m-d');
        $hlTime       = date("Y-m-d H:i:s");
        $product_id   = $isLive ? 2 : Product::getProductID($this->product->kategoria);

        $updateQuery = "UPDATE cl_hlusers.hardlock
                SET hlLan = {$lan}, hlStat = 1, hlDateIssue = '{$hlDateIssue}', hlUser = {$this->userID}, hlManID = 36, hlCtrID = '{$this->ctrID}',
                old_db = 'clusers_eng', hlTime = '{$hlTime}', product_id = {$product_id}, isFloating = {$floating}
                WHERE hlNum = '{$key}'";

        $this->db->db->query($updateQuery);
    }

    private function checkHardlockKey($key)
    {
        $hardlock = $this->db->db->query("SELECT count(prID) AS programs FROM cl_hlusers.h_programs WHERE prHlNum = '{$key}' LIMIT 1")->row();

        return $hardlock->programs > 0 == false;
    }

    private function createPerpetual()
    {
        $key        = $this->createHardlockKey(false);
        $lan        = 0;
        $floating   = 0;

        if ($this->orderData->hl_prot == 'on' && !$this->checkHardlockKey($key)) {
            $this->error = "A program already belongs to this key.";
            return false;
        }

        $verCode = $this->product->kategoria == 'live' ? $this->liveVersion->verCode : $this->version->verCode;

        if ($this->orderData->floating_lic == 'on') {
            $quantity = $this->orderData->lan_quantity == 1 ? 0 : $this->orderData->lan_quantity;
            $lan = $lan + $quantity;
            $floating = 1;

            if ($lan > 49) {
                $this->error = "Too much license. Max license number is 49";
                return false;
            }
        }

        $lanSign = Product::GetLanSignFromLanUserNumber($lan);

        $this->setPassword($key, $verCode, $this->product->type, $lanSign);

        if (!$this->keyExist($key)) {
            $this->createHardlock($key, false, $lan, $floating);
        } else {
            $this->updateHardlock($key, false, $lan, $floating);
        }

        $version = $this->product->kategoria == 'live' ? $this->liveVersion->verID : $this->version->verID;

        $progCount = $lan == 0 ? 1 : $lan;

        for ($i = 0; $i < $progCount; $i++) {
            $this->createLicense($this->serial, $this->product->type, $version, false, $lan);
        }

        if ($this->orderData->floating_lic == 'on') {
            $this->floatingEvent();
        }

        if ($this->programGenerated > 1) {
            array_push($this->serialArray, $this->serial);
        }

        return true;
    }

    function IsSoftwareKey($serial = "")
    {
        if ($serial == "") return false;

        $ph         = popen(PATH_CODEGEN . " -IsSoftwareKey " . $serial, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
        $szoftveres = fgets($ph, 1024);
        pclose($ph);

        return ($szoftveres == 'true');
    }

    private function GenerateTimeCode($password, $numOfDays)
    {
        $isid = substr($password, 0, 2) . substr($password, 7, 2);

        $nVersion = intval(substr($password, 7, 2));
        if ($nVersion > 29)
            $command = PATH_CODEGEN . " -GenerateTimeCode " . $password . " " . $isid . " " . $numOfDays;
        else
            $command = PATH_CODEGEN . " -XDay " . $password . " " . $numOfDays;

        $command    = PATH_CODEGEN . " -GenerateTimeCode " . $password . " " . $isid . " " . $numOfDays;
        $ph         = popen($command, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
        $aktkod     = fgets($ph, 1024);
        pclose($ph);

        return $aktkod;
    }

    private function floatingEvent()
    {
        $key = substr($this->serial, 0, 6);

        $history            = new stdClass();
        $history->hiHlNum   = $key;
        $history->hiDate    = date("Y-m-d");
        $history->hiManID   = 36;
        $history->hiTypeID  = 29;
        $history->hiTime    = date("Y-m-d H:i:s");
        $history->hiInfo    = "Web order, Floating bekapcsolva";

        $this->db->db->insert("cl_hlusers.h_history", $history);
    }

    private function createHistory($actDate)
    {
        $key = substr($this->serial, 0, 6);

        $history            = new stdClass();
        $history->hiHlNum   = $key;
        $history->hiDate    = date("Y-m-d");
        $history->hiManID   = 36;
        $history->hiTypeID  = 3;
        $history->hiTime    = date("Y-m-d H:i:s");
        $history->hiInfo    = "Web order, Aktiválás érvényessége: " . $actDate;

        $this->db->db->insert("cl_hlusers.h_history", $history);
    }

    private function createLicense($serial, $type, $version, $deactivated, $prLan = 0)
    {
        $key                    = substr($serial, 0, 6);
        $instalments            = $this->getInstalments();
        $type                   = $type == 'L' ? 76 : $type;
        $prStat                 = $deactivated ? 1 : 0;
        $prInvoiceRecurrence    = $instalments['reszlet'];
        $actCode                = '';

        if ($this->product->kategoria == 'nonp') {
            $contact = 5;
        } elseif ($this->product->kategoria == 'subscription') {
            $contact = 1;

            if (strpos($this->product->termek, "monthly"))
                $prInvoiceRecurrence    = 1;
            else
                $prInvoiceRecurrence    = 12;
        } else {
            $contact = 0;
        }

        if ($this->product->until != '' && $this->product->until != NULL && $this->product->akcio != '' && $this->product->akcio != NULL)
            $this->expirationDate = $this->product->until;

        if ($this->orderData->hl_prot == 'on' && !$this->IsSoftwareKey($serial)) {
            $numOfDays  = 3583; // NFF kod
            $actCode    = $this->GenerateTimeCode($serial, $numOfDays);
        }

        if ($this->product->kategoria == 'upgrade') {
            $key    = substr($serial, 0, 6);
            $prLan  = $this->getLanNumber($key);
        }

        if (Product::needPeriod($this->product->kategoria, $this->product->type, $instalments['period']) && Product::isInvoice($this->ctrID)) {
            // Reszletfizetes eseten csak 60 napra kapjak meg a programot
            $expirationDate = date('Y-m-d', strtotime(date('Y-m-d') . '+60 days'));
        } else {
            $expirationDate = $this->expirationDate;
        }

        if ($this->generatePrevProgram && (int)$version == (int)$this->version->verID - 1 && ($this->product->kategoria == 'perp' || $this->product->kategoria == 'lt')) {
            $expirationDate = date('Y') . '-05-01';
        }

        $license                        = new stdClass();
        $license->prTypeID              = $type;
        $license->prVerID               = $version;
        $license->prLan                 = $prLan;
        $license->prPass                = $serial;
        $license->prSellDate            = date("Y-m-d H:i:s");
        $license->prOrdNum              = $this->orderNumber;
        $license->prActDate             = date("Y-m-d H:i:s");
        $license->prFizetve             = $expirationDate;
        $license->prTime                = date("Y-m-d H:i:s");
        $license->prLastMod             = date("Y-m-d H:i:s");
        $license->prContact             = $contact;
        $license->prHlNum               = $key;
        $license->prManID               = 36;
        $license->prCtrID               = $this->ctrID;
        $license->prStat                = $prStat;
        $license->prActCode             = $actCode;
        $license->prInvoiceDateFrom     = date('Y-m', time());
        $license->prInvoiceDateto       = $instalments['fizHatIdo'];
        $license->prInvoiceRecurrence   = $prInvoiceRecurrence;
        $license->old_db                = 'clusers_eng';
        $license->old_prID              = 0;
        $license->prPrice               = $this->finalPrice;

        $this->db->db->insert("cl_hlusers.h_programs", $license);

        $this->createHistory($this->expirationDate);

        return ($this->db->db->affected_rows() != 1) ? false : true;
    }

    private function checkSerial($serial)
    {
        $exist = $this->db->db->query("SELECT prID FROM cl_hlusers.h_programs WHERE prPass = '{$serial}' LIMIT 1")->row();

        return !empty($exist);
    }

    private function checkProgramUpgrade()
    {
        $o_type = (int)$this->product->o_type;

        $upgrade = $this->db->db->query("SELECT * FROM cl_hlusers.o_types WHERE id = {$o_type} LIMIT 1")->row();

        return $upgrade;
    }

    private function getVersionFromSerial($serial)
    {
        $ver8And9 = (int)Product::getVer8And9FromSerial($serial);

        $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verPassword8and9 = {$ver8And9} LIMIT 1")->row();

        return $version;
    }

    private function deactivateHardlock($key)
    {
        $hlDatePro = date('Y-m-d', time());

        $updateQuery = "UPDATE cl_hlusers.hardlock
            SET hlStat = 2, hlDatePro = '{$hlDatePro}'
            WHERE hlNum = '{$key}'";

        $this->db->db->query($updateQuery);
    }

    private function deactivateProgram($serial)
    {
        $updateQuery = "UPDATE cl_hlusers.h_programs
            SET prStat = 1
            WHERE prPass = '{$serial}'";

        $this->db->db->query($updateQuery);
    }

    private function updateOldAndNewHlNum($oldHlNum, $newHlNum)
    {
        $updateQuery1 = "UPDATE cl_hlusers.hardlock
            SET hlOldHlNum = '{$oldHlNum}'
            WHERE hlNum = '{$newHlNum}'";

        $updateQuery2 = "UPDATE cl_hlusers.hardlock
            SET hlNewHlNum = '{$newHlNum}'
            WHERE hlNum = '{$oldHlNum}'";

        $this->db->db->query($updateQuery1);
        $this->db->db->query($updateQuery2);
    }

    private function changeHardlockKey($serial, $ctrKey)
    {
        $this->deactivateHardlock(substr($serial, 0, 6));

        if ($this->orderData->hl_select != '') {
            $key = $this->orderData->hl_select;
            $this->updateHardlock($key, false);
        } else {
            $key = $this->createHardlockKey($ctrKey);

            if (!$this->keyExist($key)) {
                $this->createHardlock($key, false);
            } else {
                $this->updateHardlock($key, false);
            }
        }

        $this->updateOldAndNewHlNum(substr($serial, 0, 6), $key);

        return $key;
    }

    private function getLanNumber($key)
    {
        $hl = $this->db->db->query("SELECT hlLan FROM cl_hlusers.hardlock WHERE hlNum = {$key} LIMIT 1")->row();

        return $hl->hlLan;
    }

    private function createCrossgradeOrUpgrade()
    {
        if (!$this->checkSerial($this->orderData->old_hl_number)) {
            $this->error = "Invalid serial number";
            return false;
        }

        $serialType = Product::getTypeFromSerial($this->orderData->old_hl_number);
        $upgrade    = $this->checkProgramUpgrade();

        $serialType = $upgrade->id == 21 && $serialType == 7 ? 6 : $serialType;

        if ($serialType != $upgrade->from && $serialType != 7) {
            $this->error = "Invalid type";
            return false;
        }

        $version = $this->getVersionFromSerial($this->orderData->old_hl_number);

        if ($this->product->kategoria == 'crossgrade') {
            $key        = $this->changeHardlockKey($this->orderData->old_hl_number, false);
            $verCode    = $this->version->verCode;
            $verID      = $this->version->verID;
        }

        if ($this->product->kategoria == 'upgrade') {
            $key        = substr($this->orderData->old_hl_number, 0, 6);
            $verCode    = $upgrade->to == 'L' ? $this->liveVersion->verCode : $this->version->verCode;
            $verID      = $upgrade->to == 'L' ? $this->liveVersion->verID : $this->version->verID;

            if ($upgrade->version == 0 && $version->verID == $verID && $upgrade->from == $upgrade->to) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 1 && $version->verCode + $upgrade->version < $verCode) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 2 && $version->verCode + $upgrade->version > $verCode) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 4 && ($version->verCode < 75 || $version->verCode > 77)) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 3 && $version->verCode > 74) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 5 && $version->verID != $verID - 2) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->version == 6 && $version->verID >= $verID - 2) {
                $this->error = "Invalid version";
                return false;
            }

            if ($upgrade->to == 'L')
                $this->version = $this->liveVersion;
        }

        $lan = $this->getLanNumber($key);

        if ($this->product->id == 1539 || $this->product->id == 1540) {
            $verCode = 79;
            $verID = 22;
        }

        $this->product->type = $upgrade->to;

        $this->setPassword($key, $verCode, $upgrade->to, $lan);

        if ($this->checkSerial($this->serial) && $this->product->kategoria == 'upgrade') {
            $this->error = "You already upgraded this serial number";
            return false;
        }

        $this->deactivateProgram($this->orderData->old_hl_number);

        if ($lan > 1) {
            for ($i = 0; $i < $lan; $i++) {
                $result = $this->createLicense($this->serial, $upgrade->to, $verID, false);
            }
        } else {
            $result = $this->createLicense($this->serial, $upgrade->to, $verID, false);
        }

        return $result;
    }

    private function hardlockChange()
    {
        if ($this->orderData->old_hl_number == '' || !$this->checkSerial($this->orderData->old_hl_number)) {
            $this->error = "Invalid serial number";
            return false;
        }

        $version    = $this->getVersionFromSerial($this->orderData->old_hl_number);
        $key        = $this->changeHardlockKey($this->orderData->old_hl_number, true);
        $verCode    = $version->verCode;
        $verID      = $version->verID;
        $serialType = Product::getTypeFromSerial($this->orderData->old_hl_number);
        $lan        = $this->getLanNumber($key);

        $this->setPassword($key, $verCode, $serialType, $lan);
        $this->deactivateProgram($this->orderData->old_hl_number);

        $result = $this->createLicense($this->serial, $serialType, $verID, false);

        return $result;
    }

    private function getModule()
    {
        $module = $this->db->db->query("SELECT * FROM cl_hlusers.p_mtypes WHERE ID = {$this->product->module_id} LIMIT 1")->row();

        return $module;
    }

    private function setModule($serial, $mdCode)
    {
        $command        = PATH_CODEGEN . " -Module " . $serial . " " . $mdCode;
        $ph             = popen($command, "r") or die("A 'codegen' paranccsal nem veheto fel kapcsolat");
        $this->module   = fgets($ph, 1024);
        pclose($ph);
    }

    private function moduleExist($prID, $mdCode)
    {
        $exist = $this->db->db->query("SELECT ID FROM cl_hlusers.p_modules WHERE mdPrID = {$prID} AND mdID = {$mdCode} LIMIT 1")->row();

        return !empty($exist);
    }

    private function getPrID($serial)
    {
        $program = $this->db->db->query("SELECT prID FROM cl_hlusers.h_programs WHERE prPass = '{$serial}' LIMIT 1")->row();

        return $program->prID;
    }

    private function getModulePrice($mdID)
    {
        if ($this->product->kategoria == 'subscription') {
            $module = Product::getMEPmoduleForSubscription($this->product->termek, $this->ctrID);
            return $module->price;
        }

        $module = $this->db->db->query("SELECT akcio, ackio_date, euro, usd FROM cl_hlusers.o_products WHERE lang = '{$this->ctrID}' AND module_id = {$mdID} LIMIT 1")->row();

        if ($module->akcio != '' && $module->akcio != null && date('Y-m-d') <= $module->ackio_date) {
            $module->price = $module->akcio;
        } else {
            if (substr($this->ctrID, 0, 2) == '11')
                $module->price = $module->usd;
            else
                $module->price = $module->euro;
        }

        return $module->price;
    }

    private function insertModule($mdID, $hlNum, $prID)
    {
        if ($this->product->kategoria == 'module') {
            $price = $this->product->price;
        } else {
            $price = $this->getModulePrice($mdID);
        }

        $module                 = new stdClass();
        $module->mdID           = $mdID;
        $module->mdPrID         = $prID;
        $module->mdPrHlNum      = $hlNum;
        $module->mdCode         = $this->module;
        $module->mdDate         = date("Y-m-d");
        $module->mdPrice        = $price;
        $module->mdInvNum       = '';
        $module->mdOrdNum       = $this->orderNumber;
        $module->mdIsPurchase   = 1;


        $this->db->db->insert("cl_hlusers.p_modules", $module);

        return ($this->db->db->affected_rows() != 1) ? false : true;
    }

    private function createModule()
    {
        if (!$this->checkSerial($this->orderData->old_hl_number)) {
            $this->error = "Invalid serial number";
            return false;
        }

        if ($this->product->seq == 2 && substr($this->orderData->old_hl_number, 0, 2) != 99) {
            $this->error = "Invalid serial number";
            return false;
        }

        $module = $this->getModule();
        $prID = $this->getPrID($this->orderData->old_hl_number);

        if ($module->program_types != '' && $module->program_types != null) {
            $serialType     = Product::getTypeFromSerial($this->orderData->old_hl_number);
            $moduleTypes    = explode(";", $module->program_types);

            if (!in_array($serialType, $moduleTypes)) {
                $this->error = "Invalid serial number";
                return false;
            }
        }

        $this->setModule($this->orderData->old_hl_number, $module->ID);

        if ($this->moduleExist($prID, $module->ID)) {
            $this->error = "You already have this module";
            return false;
        }

        $result = $this->insertModule($module->ID, substr($this->orderData->old_hl_number, 0, 6), $prID);

        return $result;
    }

    private function changeFloatingLan()
    {
        if (!$this->checkSerial($this->orderData->old_hl_number) || !$this->IsSoftwareKey($this->orderData->old_hl_number)) {
            $this->error = "Invalid serial number";
            return false;
        }

        $serialType = Product::getTypeFromSerial($this->orderData->old_hl_number);
        if ($serialType != $this->product->type) {
            $this->error = "Invalid type";
            return false;
        }

        if (substr($this->orderData->old_hl_number, 7, 2) < 40) {
            $this->error = "Invalid version";
            return false;
        }

        $hlNum = substr($this->orderData->old_hl_number, 0, 6);

        $hardlock = $this->db->db->query("SELECT * FROM cl_hlusers.hardlock WHERE hlNum = '{$hlNum}'")->row();

        /*if ($hardlock->isFloating == 0) {
            $this->error = "This license is not a floating license";
            return false;
        }*/

        $hlLan      = $hardlock->hlLan == 0 ? 1 : $hardlock->hlLan;
        $lan        = $hlLan + $this->orderData->lan_quantity;
        $lanSign    = Product::GetLanSignFromLanUserNumber($lan);

        if ($lan > 49) {
            $this->error = "Too much license. Max license number is 49";
            return false;
        }

        $programs = $this->db->db->query("SELECT * FROM cl_hlusers.h_programs WHERE prHlNum = '{$hlNum}' GROUP BY prPass;")->result();

        $updateQuery = "UPDATE cl_hlusers.hardlock
            SET hlLan = {$lan}
            WHERE hlNum = '{$hlNum}'";
        $this->db->db->query($updateQuery);

        foreach ($programs as $program) {
            $password   = $program->prPass;
            $type       = $program->prTypeID;
            $verID      = $program->prVerID;
            $contact    = $program->prContact;

            $version = $this->db->db->query("SELECT * FROM cl_hlusers.p_versions WHERE verID = '{$verID}';")->row();

            $this->setPassword($hlNum, $version->verCode, $type, $lanSign);

            $this->db->db->query("DELETE FROM cl_hlusers.h_programs WHERE prPass = '{$password}'");

            $license                        = new stdClass();
            $license->prTypeID              = $type;
            $license->prVerID               = $verID;
            $license->prLan                 = $lan;
            $license->prPass                = $this->serial;
            $license->prSellDate            = date("Y-m-d H:i:s");
            $license->prOrdNum              = $program->prOrdNum;
            $license->prActDate             = date("Y-m-d H:i:s");
            $license->prFizetve             = $program->prFizetve;
            $license->prTime                = date("Y-m-d H:i:s");
            $license->prLastMod             = date("Y-m-d H:i:s");
            $license->prContact             = $contact;
            $license->prHlNum               = $hlNum;
            $license->prManID               = 36;
            $license->prCtrID               = $this->ctrID;
            $license->prStat                = $program->prStat;
            $license->prActCode             = '';
            $license->prInvoiceDateFrom     = $program->prInvoiceDateFrom;
            $license->prInvoiceDateto       = $program->prInvoiceDateTo;
            $license->prInvoiceRecurrence   = $program->prInvoiceRecurrence;
            $license->old_db                = 'clusers_eng';
            $license->old_prID              = 0;
            $license->prPrice               = $this->finalPrice;
            $license->twtw                  = $program->twtw;

            for ($i = 0; $i < $lan; $i++) {
                $this->db->db->insert("cl_hlusers.h_programs", $license);
            }
        }

        return true;
    }

    private function changeToFloating()
    {
        if (!$this->checkSerial($this->orderData->old_hl_number) || !$this->IsSoftwareKey($this->orderData->old_hl_number)) {
            $this->error = "Invalid serial number";
            return false;
        }

        $serialType = Product::getTypeFromSerial($this->orderData->old_hl_number);
        if ($serialType != 8 && substr($this->orderData->old_hl_number, 0, 2) != '95') {
            $this->error = "Invalid type";
            return false;
        }

        if ($serialType != 8 && $serialType != 4) {
            $this->error = "Invalid type";
            return false;
        }

        if (substr($this->orderData->old_hl_number, 7, 2) < 40) {
            $this->error = "Invalid version";
            return false;
        }

        $hlNum = substr($this->orderData->old_hl_number, 0, 6);

        $hardlock = $this->db->db->query("SELECT * FROM cl_hlusers.hardlock WHERE hlNum = '{$hlNum}'")->row();

        if ($hardlock->isFloating == 1) {
            $this->error = "This license is already floating license";
            return false;
        }

        $updateQuery = "UPDATE cl_hlusers.hardlock
            SET isFloating = 1
            WHERE hlNum = '{$hlNum}'";
        $this->db->db->query($updateQuery);

        $this->serial = $this->orderData->old_hl_number;

        $this->floatingEvent();

        return true;
    }

    private function createSubscription()
    {
        $date       = new DateTime();
        $needLive   = $this->product->type == 'L' || $this->product->type == '4' ? true : false;
        $key        = $this->createHardlockKey($needLive);
        $needLive   = $this->product->type == 'L' ? true : false;

        if ($needLive) {
            $this->version = $this->liveVersion;
        }

        if (!$this->keyExist($key)) {
            $this->createHardlock($key, $needLive);
        } else {
            $this->updateHardlock($key, $needLive);
        }

        $this->setPassword($key, $this->version->verCode, $this->product->type);

        if (strpos($this->product->termek, "monthly")) {
            $date->modify('+3 month');
            $date->modify('+30 day');
        } else {
            $date->modify('+1 year');
            $date->modify('+30 day');
        }

        $this->expirationDate = $date->format('Y-m-d');

        $verID = $this->product->type == 'L' ? $this->liveVersion->verID : $this->version->verID;

        $result = $this->createLicense($this->serial, $this->product->type, $verID, false);

        return $result;
    }

    private function createProgram()
    {
        /*if (substr($this->ctrID, 0, 2) == '39')
            $this->generatePrevProgram = true;*/

        switch ($this->product->kategoria) {
            case 'crossgrade':
                $this->generatePrevProgram = false;
                $result = $this->createCrossgradeOrUpgrade();
                break;

            case 'upgrade':
                $this->generatePrevProgram = false;
                $result = $this->createCrossgradeOrUpgrade();
                break;

            case 'hardlock':
                $this->generatePrevProgram = false;
                $result = $this->hardlockChange();
                break;

            case 'nonp':
                $this->generatePrevProgram = false;
                $result = $this->createNonprofit();
                break;

            case 'module':
                $this->generatePrevProgram = false;
                $result = $this->createModule();
                break;

            case 'subscription':
                $this->generatePrevProgram = false;
                $result = $this->createSubscription();
                break;

            case 'floating':
                $this->generatePrevProgram = false;
                $result = $this->changeToFloating();
                break;

            case 'lan':
                $this->generatePrevProgram = false;
                $result = $this->changeFloatingLan();
                break;

            default:
                if (isset($this->product->params) && $this->product->params != '') {
                    $params = json_decode($this->product->params);
                    $this->programGenerated = isset($params->number_of_programs) && $params->number_of_programs != '' && $params->number_of_programs > 1 ? $params->number_of_programs : 1;
                }

                for ($i = 0; $i < $this->programGenerated; $i++) {
                    $result = $this->createPerpetual();
                }

                if ($this->product->kategoria == 'live')
                    $this->generatePrevProgram = false;
                break;
        }

        if (!$result)
            return false;

        if ($this->orderData->inclLive == 'on' || $this->product->incl_live == 1 || ($this->product->kategoria != 'live' && $this->product->kategoria != 'subscription'
            && strpos($this->product->termek, "LIVE")) && $this->product->o_type != 16) {
            $key = $this->createHardlockKey(true);

            if (!$this->keyExist($key)) {
                $this->createHardlock($key, true);
            }

            $this->setLivePassword($key);

            $this->createLicense($this->liveSerial, 76, $this->liveVersion->verID, false);
        }

        if ($this->generatePrevProgram && $this->product->kategoria != 'live' && !strpos($this->product->termek, "LIVE")) {
            $this->orderData->prev_softwares = (array)$this->orderData->prev_softwares;
            $prev_version = $this->version->verCode - 1;

            array_push($this->orderData->prev_softwares, (string)$prev_version);
        }

        if ($this->orderData->prev_softwares > 0) {
            $this->setPreviousPasswords(substr($this->serial, 0, 6));

            foreach ($this->prevSerials as $key => $value) {
                $this->createLicense($key, $this->product->type, $value->verID, true);
            }
        }

        if ($this->orderData->module != '') {
            $this->product->module_id = $this->orderData->module;
            $prID = $this->getPrID($this->serial);

            $this->setModule($this->serial, $this->orderData->module);

            $this->modulePrice = $this->getModulePrice($this->orderData->module);

            $this->insertModule($this->orderData->module, substr($this->serial, 0, 6), $prID);
        }

        if ($this->orderData->credit == 'on') {
            $this->updateCredit();
        }

        return $result;
    }

    private function getProductName()
    {
        if ($this->product->kategoria == 'nonp') {
            $nonp = Product::getNonprofitVersion($this->product->termek, $this->product->id);

            if ($this->product->type == 'L')
                return "LIVE Non-Profit {$nonp->ver}";
            else
                return "Non-Profit {$nonp->ver}";
        }

        return $this->product->termek;
    }

    private function sendEmail()
    {
        $currency       = substr($this->ctrID, 0, 2) == '11' ? 'USD' : 'EUR';
        $instalments    = $this->getInstalments();
        $payment        = $instalments['payment'];
        $price          = round($this->product->price);
        $productName    = $this->getProductName();

        if ($payment == '')
            $payment = "pay in full";

        $template = getEmailTemplate();

        $subject = str_replace("{COUNTRY}", $this->getCountryName(), $template->subject);
        $subject = str_replace("{ORDER_NUMBER}", $this->orderNumber, $subject);
        $subject = str_replace("{PRODUCT}", $productName, $subject);

        $body = str_replace("{EMAIL}", $this->orderData->email, $template->body);
        $body = str_replace("{NAME}", $this->orderData->name, $body);
        $body = str_replace("{INFO}", $this->orderData->info, $body);
        $body = str_replace("{PRODUCT}", $this->product->termek, $body);
        $body = str_replace("{CURRENCY}", $currency, $body);
        $body = str_replace("{FINAL_PRICE}", round($this->finalPrice), $body);
        $body = str_replace("{ORDER_NUMBER}", $this->orderNumber, $body);
        $body = str_replace("{PAYMENT}", $payment, $body);

        if ($this->product->kategoria == 'comp') {
            $body = str_replace("Information:", "Competing product name:", $body);
        }

        if ($this->product->kategoria == 'nonp' && $this->orderData->user_type == 'pot_client') {
            $subject .= ' - Client';
        }

        if ($this->product->kategoria == 'nonp' && $this->orderData->user_type == 'student') {
            $subject .= ' - Student';
        }

        if ($this->product->kategoria == 'nonp') {
            $nonpInfo = "";
            if ($this->orderData->user_type == 'pot_client') {
                $nonpInfo .= "Phone Number: <b>{$this->orderData->pot_phone}</b><br><br>";
                $nonpInfo .= "Postal Code: <b>{$this->orderData->pot_address}</b><br><br>";
                $nonpInfo .= "Address (City, street, no.): <b>{$this->orderData->pot_company_address}</b><br><br>";
                $nonpInfo .= "Company: <b>{$this->orderData->pot_company}</b><br><br>";
            } else {
                $nonpInfo .= "Name of School: <b>{$this->orderData->school_name}</b><br><br>";
                $nonpInfo .= "Name of Course: <b>{$this->orderData->course_name}</b><br><br>";
            }

            $body = str_replace("{NOTE}", "Note: In case of providing false information, Cadline reserves the right to withdraw the Non-Profit licence.<br/><br/>", $body);
            $body = str_replace("{NONP_INFO}", $nonpInfo, $body);
        } else {
            $body = str_replace("{NOTE}", "", $body);
            $body = str_replace("{NONP_INFO}", "", $body);
        }

        if ($this->product->kategoria == 'module') {
            $body = str_replace("{SERIAL}", "Module activation key: <b>{$this->module}</b>", $body);

            $prod = $this->product->seq == 1 ? 'LT or PRO license' : 'Non-Profit';
            $body = str_replace("{MODULE_SERIAL}", "Client's existing ARCHLine.XP {$prod} serial number: <b>{$this->orderData->old_hl_number}</b> <br/><br/>", $body);
        } else {
            if ($this->product->id == 1539 || $this->product->id == 1540)
                $this->version->year = 2022;

            if (!empty($this->serialArray)) {
                $serialString = implode("<br>", $this->serialArray);
                $body = str_replace("{SERIAL}", "Serial code {$this->version->year}: <b><br>{$serialString}</b><br>", $body);
            } else {
                $body = str_replace("{SERIAL}", "Serial code {$this->version->year}: <b>{$this->serial}</b>", $body);
            }

            $body = str_replace("{MODULE_SERIAL}", "", $body);
        }

        if ($this->orderData->credit == 'on')
            $body = str_replace("{CREDIT_MSG}", "Deducted credit: <b>-{$this->credit} {$currency}</b> <br/><br/>", $body);
        else
            $body = str_replace("{CREDIT_MSG}", "", $body);

        if ($this->orderData->hl_prot == 'on') {
            $hl_price = Product::getHardlockPrice($this->ctrID);

            $body = str_replace("{HARDLOCK_MSG}", "Item: <b>Hardlock</b> <br/>", $body);
            $body = str_replace("{HARDLOCK_PRICE}", "Subtotal: <b>{$hl_price} {$currency}</b> <br/><br/>", $body);
        } else {
            $body = str_replace("{HARDLOCK_MSG}", "", $body);
            $body = str_replace("{HARDLOCK_PRICE}", "", $body);
        }

        if ($this->product->incl_live == 1)
            $body = str_replace("{INCL_LIVE_MSG}", "Serial code {$this->liveVersion->year} Live: <b>{$this->liveSerial}</b> <br/>", $body);
        else
            $body = str_replace("{INCL_LIVE_MSG}", "", $body);

        if ($this->product->kategoria != 'nonp') {
            if ($this->orderData->inclLive == 'on' || ($this->product->kategoria != 'live' && $this->product->kategoria != 'subscription'
                && $this->product->kategoria != 'upgrade' && strpos($this->product->termek, "LIVE") && $this->product->incl_live == 0)) {
                $live_price = Product::getLivePrice($this->ctrID);

                $body = str_replace("{LIVE_MSG}", "Serial code {$this->liveVersion->year} Live: <b>{$this->liveSerial}</b> <br/>", $body);
                $body = str_replace("{LIVE_PRICE}", "Subtotal: <b>{$live_price} {$currency}</b> <br/><br/>", $body);

                if ($this->product->kategoria != 'live' && strpos($this->product->termek, "LIVE"))
                    $price -= $live_price;
            } else {
                $body = str_replace("{LIVE_MSG}", "", $body);
                $body = str_replace("{LIVE_PRICE}", "", $body);
            }
        } else {
            $body = str_replace("{LIVE_MSG}", "", $body);
            $body = str_replace("{LIVE_PRICE}", "", $body);
        }

        if ($this->orderData->floating_lic == 'on') {
            $floatingPrice = Product::getFloatingPrice($this->ctrID);

            $body = str_replace("{FLOATING_MSG}", "Item: <b>Floating license</b> <br/>", $body);
            $body = str_replace("{FLOATING_PRICE}", "Subtotal: <b>{$floatingPrice} {$currency}</b> <br/><br/>", $body);
        } else {
            $body = str_replace("{FLOATING_MSG}", "", $body);
            $body = str_replace("{FLOATING_PRICE}", "", $body);
        }

        if ($this->orderData->prev_softwares > 0) {
            $prevSoftwarePrice  = Product::getPrevSoftwarePrice($this->ctrID);
            $prevSoftwareMsg    = "";

            foreach ($this->prevSerials as $key => $value) {
                $prevSoftwareMsg .= "Serial code {$value->year}: <b>{$key}</b> <br/>";
            }

            $prevSoftwareMsg .= "Subtotal: <b>{$prevSoftwarePrice} {$currency}</b> <br/><br/>";

            $body = str_replace("{PREV_SOFTWARE_MSG}", $prevSoftwareMsg, $body);
        } else {
            $body = str_replace("{PREV_SOFTWARE_MSG}", "", $body);
        }

        if ($this->orderData->module != '') {
            $module = $this->getModule();
            $modulePrice = $this->getModulePrice($this->orderData->module);

            $body = str_replace("{MODULE_MSG}", "{$module->mdtNameEng} Module activation key: <b>{$this->module}</b> <br/>", $body);
            $body = str_replace("{MODULE_PRICE}", "Subtotal: <b>{$modulePrice} {$currency} {EACH}</b> <br/><br/>", $body);
        } else {
            $body = str_replace("{MODULE_MSG}", "", $body);
            $body = str_replace("{MODULE_PRICE}", "", $body);
        }

        if ($this->product->kategoria == 'subscription') {
            $subscriptionMsg = Product::getSubscriptionInfo($this->product->termek);

            $datetime = new DateTime($this->expirationDate);
            $datetime->modify('-30 day');

            $to         = $datetime->format('t/m/Y');
            $expDate    = 'Renewal date: <b>' . $to . '</b>';

            $body = str_replace("{SUBSCRIPTION_MSG}", $subscriptionMsg . '<br/><br/>', $body);
            $body = str_replace("{SUBSCRIPTION_RENEWAL}", $expDate . '<br/>', $body);
        } else {
            $body = str_replace("{SUBSCRIPTION_MSG}", "", $body);
            $body = str_replace("{SUBSCRIPTION_RENEWAL}", "", $body);
        }

        if ($this->product->kategoria == 'subscription' && strpos($this->product->termek, "monthly"))
            $body = str_replace("{EACH}", "each", $body);
        else
            $body = str_replace("{EACH}", "", $body);

        if ($this->product->kategoria == 'nonp' && $this->customExpDate != '') {
            if ($this->orderData->user_type == 'pot_client') {
                $customDate = date_create($this->expirationDate);
                $expirationDate = date_format($customDate, "d/m/Y");

                $body = str_replace("{NONP_MSG}", "Requested expiry date (maximum 30 days allowed): <b>{$expirationDate}</b><br/><br/>", $body);
            } else {
                $body = str_replace("{NONP_MSG}", "Requested expiry date (set up by Cadline Office manually): <b>{$this->customExpDate}</b><br/><br/>", $body);
            }
        } else {
            if ($this->needDate && $this->product->kategoria == 'nonp' && $this->customExpDate == '' && substr($this->ctrID, 0, 2) != 39) {
                $customDate = date_create($this->expirationDate);
                $expirationDate = date_format($customDate, "d/m/Y");

                if ($this->orderData->user_type == 'student') {
                    $body = str_replace("{NONP_MSG}", "Requested expiry date: <b>{$expirationDate}</b><br/><br/>", $body);
                } else {
                    $body = str_replace("{NONP_MSG}", "Requested expiry date (maximum 30 days allowed): <b>{$expirationDate}</b><br/><br/>", $body);
                }
            } else {
                $body = str_replace("{NONP_MSG}", "", $body);
            }
        }

        if ($this->orderData->lan_quantity && $this->orderData->lan_quantity > 1) {
            if ($this->product->kategoria == 'lan') {
                $prodPrice = $price * $this->orderData->lan_quantity;
                $body = str_replace("{QUANTITY_MSG}", "Quantity: " . $this->orderData->lan_quantity . '<br>', $body);
                $body = str_replace("{PRODUCT_PRICE}", $prodPrice, $body);

                $body = str_replace("{LAN_UPGRADE_MSG}", "", $body);
                $body = str_replace("{LAN_UPGRADE_PRICE}", "", $body);
            } else {
                $lanPrice = Product::getLanPrice($this->ctrID, $this->product->type);
                $quantity = $this->orderData->lan_quantity - 1;
                $prodPrice = $lanPrice * $quantity;

                $lanMsg = "Item: <b>Next licenses</b> <br/>";
                $lanMsg .= "Quantity: {$quantity} <br>";
                $body = str_replace("{LAN_UPGRADE_MSG}", $lanMsg, $body);
                $body = str_replace("{LAN_UPGRADE_PRICE}", "Subtotal: <b>{$prodPrice} {$currency}</b> <br/><br/>", $body);

                $body = str_replace("{QUANTITY_MSG}", "", $body);
                $body = str_replace("{PRODUCT_PRICE}", $price, $body);
            }
        } else {
            $body = str_replace("{QUANTITY_MSG}", "", $body);
            $body = str_replace("{PRODUCT_PRICE}", $price, $body);
            $body = str_replace("{LAN_UPGRADE_MSG}", "", $body);
            $body = str_replace("{LAN_UPGRADE_PRICE}", "", $body);
        }

        sendEmail('info@archlinexp.com', 'info@archlinexp.com', $this->partnerEmail, $subject, $body, $this->partnerSubEmail, $this->ctrID);

        return true;
    }

    private function getNonprofitVer8And9()
    {
        $nonp = Product::getNonprofitVersion($this->product->termek, $this->product->id);

        $ver = $this->db->db->query("SELECT p.* FROM cl_hlusers.p_versions p WHERE p.year = '{$nonp->ver}'")->row();

        $this->version = $ver;

        return $ver;
    }

    private function nonprofitExist()
    {
        if (strpos($this->product->termek, "LIVE"))
            $prg_product_id = 2;
        else
            $prg_product_id = 1;

        $userID = (int)$this->userID;

        $vcode = $this->getNonprofitVer8And9();

        $query = "SELECT SUBSTRING(prPass, 8, 2) AS prPass FROM cl_hlusers.h_programs WHERE prHlNum IN 
            (SELECT hlNum FROM cl_hlusers.hardlock WHERE hlUser = {$userID} AND product_id = {$prg_product_id}) 
            AND prHlNum LIKE '99%' AND prTypeID = '{$this->product->type}' AND prVerID = '{$vcode->verID}'";
        $nonp = $this->db->db->query($query)->row();

        return !empty($nonp);
    }

    private function createNonprofit()
    {
        $isLive = strpos($this->product->termek, "LIVE") ? true : false;

        $userID = (int)$this->userID;

        if (strpos($this->product->termek, "LIVE"))
            $prg_product_id = 2;
        else
            $prg_product_id = 1;

        $query = "SELECT SUBSTRING(prPass, 8, 2) AS prPass, prHlNum FROM cl_hlusers.h_programs WHERE prHlNum IN 
            (SELECT hlNum FROM cl_hlusers.hardlock WHERE hlUser = {$userID} AND product_id = {$prg_product_id}) 
            AND prHlNum LIKE '99%' AND prTypeID = '{$this->product->type}'";
        $nonp = $this->db->db->query($query)->row();

        if (!empty($nonp)) {
            $updateQuery = "UPDATE cl_hlusers.h_programs
                SET prStat = 1
                WHERE prHlNum = '{$nonp->prHlNum}'";

            $this->db->db->query($updateQuery);
        }

        $emptyKey = $this->db->db->query("SELECT * FROM cl_hlusers.hardlock WHERE hlNum LIKE '99%' AND hlStat = 0")->row();

        if (!empty($nonp))
            $key = $nonp->prHlNum;
        elseif (!empty($emptyKey))
            $key = $emptyKey->hlNum;
        else
            $key = $this->createHardlockKey(false);

        $this->updateHardlock($key, $isLive);
        $this->setPassword($key, $this->version->verCode, $this->product->type);

        $version = $this->version->verID;

        if ($this->product->id == 700 || $this->product->id == 701 || $this->product->id == 702 || $this->product->id == 2036 || $this->product->id == 2037) {
            $date                   = new DateTime("+12 months");
            $this->expirationDate   = $date->format("Y-m-d");
        } else {
            $actDate = $this->orderData->user_type == 'pot_client' ? date('Y-m-d', strtotime(date('Y-m-d') . '+30 days')) : date('Y-m-d', strtotime(date('Y-m-d') . '+60 days'));
            $this->expirationDate = $actDate;

            if ($this->orderData->custom_date != '') {
                $customDate = date_create($this->orderData->custom_date);
                $expire     = date_format($customDate, "Y-m-d");

                if ($expire > $actDate) {
                    $this->customExpDate = date_format($customDate, "d/m/Y");
                } else {
                    $this->expirationDate = $expire;
                    $this->needDate = true;
                }

                if (substr($this->ctrID, 0, 2) == 39 || substr($this->ctrID, 0, 2) == 37) {
                    $this->expirationDate = $expire;
                    $this->customExpDate = '';
                }
            }
        }

        if ($this->orderData->user_type == 'pot_client') {
            $phoneNumber    = addslashes($this->phoneCorrect($this->orderData->pot_phone));
            $strInfo        = addslashes("OrderPotentialClient: {$this->orderData->pot_company_address}");
            $company        = addslashes($this->orderData->pot_company);
            $strZip         = addslashes($this->orderData->pot_address);

            $updateQuery = "UPDATE cl_hlusers.users
                SET strTel = '{$phoneNumber}', strInfo = '{$strInfo}', 
                    strCompany = '{$company}', strZip = '{$strZip}'
                WHERE nUserID = '{$this->userID}' LIMIT 1;";

            $this->db->db->query($updateQuery);
        }

        if ($this->orderData->user_type == 'student') {
            $education  = addslashes("{$this->orderData->school_name}, {$this->orderData->course_name}");

            $updateQuery = "UPDATE cl_hlusers.users
                SET strInfo = 'OrderStudent', strEducation = '{$education}'
                WHERE nUserID = '{$this->userID}' LIMIT 1;";
            $this->db->db->query($updateQuery);
        }

        $result = $this->createLicense($this->serial, $this->product->type, $version, false);

        return $result;
    }

    private function tryToAlloc($min = 990001, $max = 999999)
    {
        $ret = 0;
        if ((int)$min == 0 || (int)$max == 0) return $ret;

        $query = "SELECT LEFT(hlNum, 6) AS hlNum FROM cl_hlusers.hardlock WHERE hlNum >= " . (int)$min . " AND hlNum < " . (int)$max . " ORDER BY hlNum;";
        $res = $this->db->db->query($query)->result();

        if (count($res)) {
            $keszlet = range($min, $max);
            foreach ($res as $r) $kulcsok[] = $r->hlNum;

            $diff = array_diff($keszlet, $kulcsok);
            reset($diff);
            $ret = current($diff);
        }
        return $ret;
    }

    private function getCountryName()
    {
        $ctr = substr($this->ctrID, 0, 2);
        $country = $this->db->db->query("SELECT ctrNameEng FROM cl_hlusers.countries WHERE ctrID = '{$ctr}'")->row();

        return $country->ctrNameEng;
    }

    private function uploadReceipt()
    {
        $fileName       = $this->orderData->file->name;
        $targetDir      = $_SERVER['DOCUMENT_ROOT'];
        $targetFilePath = $targetDir . "/" . $fileName;
        $allowTypes     = array('jpg', 'png', 'jpeg', 'gif', 'pdf', 'docx', 'doc', 'txt', 'bmp');
        $fileType       = pathinfo($fileName, PATHINFO_EXTENSION);

        if (!in_array($fileType, $allowTypes)) {
            $this->error = "Unknown file extension";
            return false;
        }

        if (!move_uploaded_file($this->orderData->file->tmp_name, $targetFilePath)) {
            $this->error = "Error in file uploading";
            return false;
        }

        $ctrName    = $this->getCountryName();
        $file_info  = Product::getFileInfo($this->product->id, $this->product->kategoria);

        if ($this->ctrID == '37')
            $to = 'mate.nagy@cadline.hu';
        else
            $to = 'office@cadline.hu';

        $from           = 'partnering@archlinexp.com';
        $fromName       = 'ARCHLineXP Retail Store';
        $subject        = 'Attachment for order: ' . $ctrName . ' ' . $this->orderNumber;
        $file           = $targetFilePath;
        $htmlContent    = '<h1>' . $file_info . '</h1>';
        $headers        = "From: $fromName" . " <" . $from . ">";
        $semi_rand      = md5(time());
        $mime_boundary  = "==Multipart_Boundary_x{$semi_rand}x";

        $headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";
        $message = "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"UTF-8\"\n" .
            "Content-Transfer-Encoding: 7bit\n\n" . $htmlContent . "\n\n";

        if (!empty($file) > 0) {
            if (is_file($file)) {
                $message .= "--{$mime_boundary}\n";
                $fp =    @fopen($file, "rb");
                $data =  @fread($fp, filesize($file));

                @fclose($fp);
                $data = chunk_split(base64_encode($data));
                $message .= "Content-Type: application/octet-stream; name=\"" . basename($file) . "\"\n" .
                    "Content-Disposition: attachment;\n" . " filename=\"" . basename($file) . "\"; size=" . filesize($file) . ";\n" .
                    "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
            }
        }

        $returnpath = "-f" . $from;

        $mail = @mail($to, $subject, $message, $headers, $returnpath);

        if (function_exists('curl_file_create')) {
            $cFile = curl_file_create($file, $this->orderData->file->type, basename($file));

            $post = [
                'file_content'  => $cFile,
                'action'        => 'uploadFile',
                'nUserID'       => $this->userID,
                'file_info'     => $file_info
            ];

            $login      = 'mate.nagy@cadline.hu';
            $password   = 'Mng67otf';
            $url        = 'https://crm.cadline.hu/imre.php';
            $ch         = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
            curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
            curl_setopt($ch, CURLOPT_USERPWD, "$login:$password");

            $result = curl_exec($ch);

            curl_close($ch);
        }

        unlink($targetFilePath);

        return true;
    }

    private function uploadCertification()
    {
        if (!$this->orderData->file) {
            $this->error = "Please upload a certification";
            return false;
        }

        $fileName       = $this->orderData->file->name;
        $targetDir      = $_SERVER['DOCUMENT_ROOT'];
        $targetFilePath = $targetDir . "/" . $fileName;
        $allowTypes     = array('jpg', 'png', 'jpeg', 'pdf', 'bmp');
        $fileType       = pathinfo($fileName, PATHINFO_EXTENSION);

        if (!in_array($fileType, $allowTypes)) {
            $this->error = "Unknown file extension";
            return false;
        }

        if (!move_uploaded_file($this->orderData->file->tmp_name, $targetFilePath)) {
            $this->error = "Error in file uploading";
            return false;
        }

        $ctrName    = $this->getCountryName();
        $file_info  = Product::getFileInfo($this->product->id, $this->product->kategoria);

        if ($this->ctrID == '37')
            $to = 'mate.nagy@cadline.hu';
        else
            $to = 'office@cadline.hu';

        $from           = 'partnering@archlinexp.com';
        $fromName       = 'ARCHLineXP Retail Store';
        $subject        = 'Attachment for order: ' . $ctrName . ' ' . $this->orderNumber . ' - Student';
        $file           = $targetFilePath;
        $htmlContent    = '<h1>' . $file_info . '</h1>';
        $headers        = "From: $fromName" . " <" . $from . ">";
        $semi_rand      = md5(time());
        $mime_boundary  = "==Multipart_Boundary_x{$semi_rand}x";

        $headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";
        $message = "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"UTF-8\"\n" .
            "Content-Transfer-Encoding: 7bit\n\n" . $htmlContent . "\n\n";

        if (!empty($file) > 0) {
            if (is_file($file)) {
                $message .= "--{$mime_boundary}\n";
                $fp =    @fopen($file, "rb");
                $data =  @fread($fp, filesize($file));

                @fclose($fp);
                $data = chunk_split(base64_encode($data));
                $message .= "Content-Type: application/octet-stream; name=\"" . basename($file) . "\"\n" .
                    "Content-Disposition: attachment;\n" . " filename=\"" . basename($file) . "\"; size=" . filesize($file) . ";\n" .
                    "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
            }
        }

        $returnpath = "-f" . $from;

        $mail = @mail($to, $subject, $message, $headers, $returnpath);

        if (function_exists('curl_file_create')) {
            $cFile = curl_file_create($file, $this->orderData->file->type, basename($file));

            $post = [
                'file_content'  => $cFile,
                'action'        => 'uploadFile',
                'nUserID'       => $this->userID,
                'file_info'     => $file_info
            ];

            $login      = 'mate.nagy@cadline.hu';
            $password   = 'Mng67otf';
            $url        = 'https://crm.cadline.hu/imre.php';
            $ch         = curl_init();

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
            curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
            curl_setopt($ch, CURLOPT_USERPWD, "$login:$password");

            $result = curl_exec($ch);

            curl_close($ch);
        }

        unlink($targetFilePath);

        return true;
    }

    private function getInvoiceItemID()
    {
        $web_prod = $this->db->db->query("SELECT product_id FROM szamla_agent.web_product WHERE web_id = {$this->product->id}")->row();

        return $web_prod;
    }

    private function createInvoice($web_prod_id)
    {
        $invoiceData                = new stdClass();
        $invoiceData->id            = $this->product->id;
        $invoiceData->name          = $this->orderData->name;
        $invoiceData->hlNum         = substr($this->serial, 0, 6);
        $invoiceData->orderNumber   = $this->orderNumber;
        $invoiceData->productID     = $web_prod_id;
        $invoiceData->price         = round($this->product->price);
        $invoiceData->module        = false;
        $invoiceData->prevSoftware  = $this->orderData->prev_softwares > 0;
        $invoiceData->live          = $this->orderData->inclLive == 'on';
        $invoiceData->credit        = $this->orderData->credit == 'on';
        $invoiceData->hardlock      = $this->orderData->hl_prot == 'on';
        $invoiceData->category      = $this->product->kategoria;
        $invoiceData->sub           = false;
        $invoiceData->inclLive      = $this->product->incl_live == 1;
        $invoiceData->floating_lic  = $this->orderData->floating_lic == 'on';
        $invoiceData->lan           = $this->product->kategoria == 'lan' || $this->orderData->lan_quantity > 1 ? $this->orderData->lan_quantity : false;
        $invoiceData->type          = $this->product->type;
        $invoiceData->serialArray   = $this->serialArray;

        if ($this->product->kategoria == 'subscription') {
            $invoiceData->expirationDate = $this->expirationDate;

            if (strpos($this->product->termek, "monthly")) {
                $invoiceData->sub       = true;
                $invoiceData->quantity  = 3;
            }
        }

        if ($this->orderData->module != '') {
            $module = $this->getModule();

            $invoiceData->module        = $module->mdtNameEng;
            $invoiceData->modulePrice   = $this->getModulePrice($this->orderData->module);
        }

        if ($this->product->kategoria == 'module')
            $invoiceData->hlNum = substr($this->orderData->old_hl_number, 0, 6);

        if ($invoiceData->live || $this->product->incl_live == 1)
            $invoiceData->hlNumLive = substr($this->liveSerial, 0, 6);

        if ($invoiceData->credit)
            $invoiceData->creditPrice = $this->credit;

        $instalments = $this->getInstalments();

        $szamlaAgent = new SzamlaAgent($this->ctrID, $invoiceData, $instalments['period']);

        if (!$szamlaAgent->createInvoice()) {
            $this->error = $szamlaAgent->error;
            return false;
        }

        return true;
    }

    function orderProduct()
    {
        $result             = array();
        $result['success']  = true;
        $result['error']    = '';

        if (!$this->canOrder()) {
            $result['success']  = false;
            $result['error']    = $this->error;

            return $result;
        }

        if ($this->orderData->module == 'on')
            $this->orderData->module = 16;
        else
            $this->orderData->module = '';

        $this->setUserID();
        $this->updateFinalPrice();

        if ($this->product->kategoria == 'nonp' && $this->nonprofitExist()) {
            $ctrName    = $this->getCountryName();
            $error      = "You already have a non-profit key for this account registered with this email. Please register another account";

            sendErrorEmail($ctrName, $this->product->termek, $this->orderData->name, $this->orderData->email, $error, 'Weborder - Non-Profit exist');

            $result['success']  = false;
            $result['error']    = $error;

            return $result;
        }

        if ($this->orderData->user_type != 'pot_client' && Product::needCertification($this->orderData->product_id, $this->product->kategoria) && !$this->uploadCertification()) {
            $result['success']  = false;
            $result['error']    = $this->error;

            return $result;
        }

        if (!$this->createProgram()) {
            $result['success']  = false;
            $result['error']    = $this->error;

            return $result;
        }

        if ($this->product->kategoria == 'comp' && $this->orderData->file) {
            if (!$this->uploadReceipt()) {
                $result['success']  = false;
                $result['error']    = $this->error;

                return $result;
            }
        }

        $this->createOrder();
        $this->sendEmail();

        if ($this->product->price > 0 && Product::isInvoice($this->ctrID)) {
            $web_prod = $this->getInvoiceItemID();

            if (!empty($web_prod)) {
                if (!$this->createInvoice($web_prod->product_id)) {
                    $result['success']  = false;
                    $result['error']    = $this->error;

                    return $result;
                }
            }
        }

        return $result;
    }
}
