<?php 
class GiftCode{

    function __construct() {
		
        # Get Classes
        # ---------------
        # Common Class
		$this->common = new common();
		# Database Class
		$this->dB = Connection::Database('MuOnline');

    }

    public function SetDefaultClass($Character_Class){
        switch($Character_Class){
            case 0: $ClasePJ = 0; break;        // SM
            case 1: $ClasePJ = 0; break;        // SM
            case 2: $ClasePJ = 0; break;        // SM
            case 3: $ClasePJ = 0; break;        // SM
            case 16: $ClasePJ = 16; break;      // BK
            case 17: $ClasePJ = 16; break;      // BK
            case 18: $ClasePJ = 16; break;      // BK
            case 19: $ClasePJ = 16; break;      // BK
            case 32: $ClasePJ = 32; break;      // ELF
            case 33: $ClasePJ = 32; break;      // ELF
            case 34: $ClasePJ = 32; break;      // ELF
            case 35: $ClasePJ = 32; break;      // ELF
            case 48: $ClasePJ = 48; break;      // MG
            case 49: $ClasePJ = 48; break;      // MG
            case 50: $ClasePJ = 48; break;      // MG
            case 64: $ClasePJ = 64; break;      // DL
            case 65: $ClasePJ = 64; break;      // DL
            case 66: $ClasePJ = 64; break;      // DL
            case 80: $ClasePJ = 80; break;      // SUM
            case 81: $ClasePJ = 80; break;      // SUM
            case 82: $ClasePJ = 80; break;      // SUM
            case 83: $ClasePJ = 80; break;      // SUM
            case 96: $ClasePJ = 96; break;      // RF
            case 97: $ClasePJ = 96; break;      // RF
            case 98: $ClasePJ = 96; break;      // RF
            default:
                $ClasePJ = 0;
        }
        return $ClasePJ;
    }

    public function GetStatsChar($Character_Class){
        $StatsChar = $this->dB->query_fetch_single("SELECT * FROM DefaultClassType WHERE Class = ?", array($Character_Class));
        if(!is_array($StatsChar)) return;
        return $StatsChar;
    }

    public function GetClassChar($Character_Name){
        $ClassChar = $this->dB->query_fetch_single("SELECT Class FROM Character WHERE Name = ?", array($Character_Name));
        if(!is_array($ClassChar)) return;
        return $ClassChar;
    }

    public function CheckCodeGift($codigo) {
        if(!check_value($codigo)) return;
        $GiftCode = $this->dB->query_fetch_single("SELECT * FROM WEBENGINE_GIFT_CODE WHERE Codigo = ?", array($codigo));
        if(!is_array($GiftCode)) return;
        return $GiftCode;
    }

    public function CheckAccCharLOGS($Username,$Character_Name,$Codigo){
        if(!check_value($Username)) return;
        if(!check_value($Character_Name)) return;
        if(!check_value($Codigo)) return;
        $AccChar = $this->dB->query_fetch_single("SELECT * FROM WEBENGINE_GIFT_CODE_LOGS WHERE Codigo = ?", array($Codigo));
        if(!is_array($AccChar)) return;
        return $AccChar;
    }
    public function GetLogs()
    {
        $result = $this->dB->query_fetch("SELECT * FROM WEBENGINE_GIFT_CODE_LOGS ORDER BY id DESC");
        if(!is_array($result)) return;
        return $result;
    }

    private function UserUsedCode($codigo, $Username) {
		$result = $this->dB->query_fetch_single("SELECT * FROM WEBENGINE_GIFT_CODE_LOGS WHERE Codigo = ? AND Usuario = ?", array($codigo, $Username));
		if(!is_array($result)) return;
		return true;
	}

    private function CharUsedCode($codigo, $Character_Name) {
		$result = $this->dB->query_fetch_single("SELECT * FROM WEBENGINE_GIFT_CODE_LOGS WHERE Codigo = ? AND Personaje = ?", array($codigo, $Character_Name));
		if(!is_array($result)) return;
		return true;
	}

    public function Verificaciones($Username,$Character_Name,$Codigo){
        try{
            if(!check_value($Username)) throw new Exception("<b>[GIFT Code]</b> Se ha producido un error inesperado, por favor, intente nuevamente.");
            if(!check_value($Character_Name)) throw new Exception("<b>[GIFT Code]</b> Se ha producido un error inesperado, por favor, intente nuevamente.");
            if(!Validator::UsernameLength($Username)) throw new Exception("<b>[GIFT Code]</b> Se ha producido un error inesperado, por favor, intente nuevamente.");
            if(!Validator::AlphaNumeric($Username)) throw new Exception("<b>[GIFT Code]</b> Se ha producido un error inesperado, por favor, intente nuevamente.");
            if(!Validator::AlphaNumeric($Codigo)) throw new Exception("<b>[GIFT Code]</b> Se ha producido un error inesperado, por favor, intente nuevamente.");
            if(!check_value($Codigo)) throw new Exception("<b>[GIFT Code]</b> El codigo no es correcto.");
            if($this->common->accountOnline($Username)) throw new Exception("<b>[GIFT Code]</b> Debes estar desconectado.");

            $CodeGifResult      = $this->CheckCodeGift($Codigo);
            $AccCharResultLogs  = $this->CheckAccCharLOGS($Username,$Character_Name,$Codigo);

            if($CodeGifResult['Codigo'] != $Codigo) throw new Exception("<b>[GIFT Code]</b> El codigo no es correcto.");
            if($CodeGifResult['UsedActual'] >= $CodeGifResult['UsedMax']) throw new Exception("<b>[GIFT Code]</b> El codigo ya fue usado el maximo de veces disponibles.");
            if($this->UserUsedCode($Codigo, $Username)) throw new Exception("<b>[GIFT Code]</b> Esta cuenta ya reclamo este codigo.");
            if($this->CharUsedCode($Codigo, $Character_Name)) throw new Exception("<b>[GIFT Code]</b> Este personaje ya reclamo este codigo.");
            if($CodeGifResult['Usuario'] != '0') { if($CodeGifResult['Usuario'] != $Username ) throw new Exception("<b>[GIFT Code]</b> No puedes usar este codigo en esta cuenta."); }
            if($CodeGifResult['Personaje'] != '0') { if($CodeGifResult['Personaje'] != $Character_Name ) throw new Exception("<b>[GIFT Code]</b> No puedes usar este codigo en este personaje."); }

            $this->GiftCode($Username,$Character_Name,$Codigo);

        }catch(Exception $ex) {
            message('error', $ex->getMessage());
        }
    }

    public function GiftCode($Username,$Character_Name,$Codigo) {
        try {
            date_default_timezone_set('America\Argentina\Tucuman');
            $Fecha = date('Y-m-d H:i:s',time());
            $CodeGifResult = $this->CheckCodeGift($Codigo);
            $AccCharResult = $this->CheckAccCharLOGS($Username,$Character_Name,$Codigo);

            # Query Recompensas
            $SetCharRec         =   "UPDATE "._TBL_CHR_." SET ";
            if($CodeGifResult['TypeCode'] == 1){

                $GetClassChar  = $this->GetClassChar($Character_Name);
                $SetDefaultClass = $this->SetDefaultClass($GetClassChar['Class']);
                $GetStats = $this->GetStatsChar($SetDefaultClass);   

                $SetCharRec        .=   ""._CLMN_CHR_LVL_." = ".$CodeGifResult['Niveles'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_RSTS_." = ".$CodeGifResult['Resets'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_GRSTS_." = ".$CodeGifResult['MResets'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_STAT_STR_." = ".$GetStats['Strength'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_STAT_AGI_." = ".$GetStats['Dexterity'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_STAT_VIT_." = ".$GetStats['Vitality'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_STAT_ENE_." = ".$GetStats['Energy'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_STAT_CMD_." = ".$GetStats['Leadership'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_LVLUP_POINT_." = ".$CodeGifResult['pLevel']." ";
            }else{
                $SetCharRec        .=   ""._CLMN_CHR_LVL_." = "._CLMN_CHR_LVL_."+".$CodeGifResult['Niveles'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_RSTS_." = "._CLMN_CHR_RSTS_."+".$CodeGifResult['Resets'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_GRSTS_." = "._CLMN_CHR_GRSTS_."+".$CodeGifResult['MResets'].", ";
                $SetCharRec        .=   ""._CLMN_CHR_LVLUP_POINT_." = "._CLMN_CHR_LVLUP_POINT_."+".$CodeGifResult['pLevel']." ";
            }
            $SetCharRec        .=   "WHERE "._CLMN_CHR_NAME_."='".$Character_Name."'  ";
            $CharRecResult      =   $this->dB->query_fetch_single($SetCharRec);

            # Query Coins
            if($CodeGifResult['Coins'] > 0){
                $SetCoinRec         =   "UPDATE CashShopData ";
                $SetCoinRec        .=   "SET ".$CodeGifResult['TypeCoin']." = ".$CodeGifResult['TypeCoin']."+".$CodeGifResult['Coins']." ";
                $SetCoinRec        .=   "WHERE AccountID = '".$Username."' ";
                $CoinRecResult      =   $this->dB->query_fetch_single($SetCoinRec);
            }

            # Query Vip
            if($CodeGifResult['VipDays'] > 0){
                $SetVipRec          =   "UPDATE "._TBL_MI_." ";
                $SetVipRec         .=   "SET "._CLMN_VIP_TYPE_." = ".$CodeGifResult['VipType'].", ";
                $SetVipRec         .=   ""._CLMN_VIP_DATE_." = GETDATE() + ".$CodeGifResult['VipDays']." ";
                $SetVipRec         .=   "WHERE "._CLMN_MS_MEMBID_." = '".$Username."'";
                $VipRecResult       =   $this->dB->query_fetch_single($SetVipRec);
            }

            # Query Items
            if($CodeGifResult['DarItem'] == 1){
                if($CodeGifResult['TypeWare'] == 1){
                    $this->SetItemGremoryCase($Username,$Character_Name,$CodeGifResult['iGroup'],$CodeGifResult['iIndex'],$CodeGifResult['iLevel']);
                }else{
                    $this->InsertItemWarehouse($Username,$CodeGifResult['iLevel'],255,0,0,0,0,0,0,0,255,255,255,255,255,$CodeGifResult['iGroup'],$CodeGifResult['iIndex']);
                }
            }

            # Query Gift Code
            $UpdateGiftCode         =   "UPDATE WEBENGINE_GIFT_CODE SET UsedActual = UsedActual+1 WHERE Codigo = '".$CodeGifResult['Codigo']."'";
            $UPGiftCodeResult       =   $this->dB->query_fetch_single($UpdateGiftCode);

            # Query Insert Logs
            $InsertGiftCodeLogs     =   "INSERT INTO WEBENGINE_GIFT_CODE_LOGS (Codigo, Usuario, Personaje, Fecha) ";
            $InsertGiftCodeLogs    .=   "VALUES ('".$CodeGifResult['Codigo']."', '".$Username."','".$Character_Name."', '".$Fecha."')";
            $GiftCodeInsert         =   $this->dB->query_fetch_single($InsertGiftCodeLogs);
            
            // Success
            if($CodeGifResult['VipType'] == 1) $TipoVip = 'Bronce';
            else if($CodeGifResult['VipType'] == 2) $TipoVip = 'Plata';
            else if($CodeGifResult['VipType'] == 3) $TipoVip = 'Oro';

            $Msg                    =   "<b>[GIFT Code]</b> Felicidades, has obtenido con exito las siguientes recompensas<br>";
            if($CodeGifResult['pLevel'] > 0 || $CodeGifResult['Resets'] > 0 || $CodeGifResult['MResets'] > 0) $Msg .=   "<b>[ Personaje ]</b>: <br>";
            if($CodeGifResult['pLevel'] > 0)    $Msg .=   "<b>- Puntos para repartir:</b> +".number_format($CodeGifResult['pLevel'],0,',','.')."<br>";
            if($CodeGifResult['Niveles'] > 0)    $Msg .=   "<b>- Nivel:</b> +".number_format($CodeGifResult['Niveles'],0,',','.')."<br>";
            if($CodeGifResult['Resets'] > 0)    $Msg .=   "<b>- Resets:</b> +".number_format($CodeGifResult['Resets'],0,',','.')."<br>";
            if($CodeGifResult['MResets'] > 0)   $Msg .=   "<b>- Master Resets:</b> +".number_format($CodeGifResult['MResets'],0,',','.')."<br>";
            if($CodeGifResult['VipDays'] > 0 || $CodeGifResult['Coins'] > 0)   $Msg .=   "<b>[ Cuenta ]</b>:<br>";
            if($CodeGifResult['VipDays'] > 0)   $Msg .=   "<b>- Vip:</b> ".number_format($CodeGifResult['VipDays'],0,',','.')." dias de <b>Vip ".$TipoVip."</b><br>";
            if($CodeGifResult['Coins'] > 0)     $Msg .=   "<b>- Coins:</b> +".number_format($CodeGifResult['Coins'],0,',','.')." ".$CodeGifResult['TypeCoin']."<br>";
            if($CodeGifResult['DarItem'] == 1)  $Msg .=   "<b>[ Items ]</b>:<br>";
            if($CodeGifResult['DarItem'] == 1)  $Msg .=   "<b>- Item:</b> ".$CodeGifResult['iName']."<br>";

            message('success',$Msg);
        } catch(Exception $ex) {
            message('error', $ex->getMessage());
        }	
        
    }

    public function SetItemGremoryCase($Username,$Character_Name,$ItemiGroup,$ItemiIndex,$ItemiLevel) {

        $ItemFinalIndex 	= 		(($ItemiGroup*512) + $ItemiIndex);

        $SetItemRec         = "declare @v_time datetime = '1970-01-01 00:00:00' ";
        $SetItemRec        .= "declare @v_date1 datetime = GETDATE(); ";
        $SetItemRec        .= "declare @v_date2 datetime = GETDATE() + 20; ";
        $SetItemRec        .= "declare @Final_date1 bigint ";
        $SetItemRec        .= "declare @Final_date2 bigint ";
        $SetItemRec        .= "select @Final_date1 = datediff(s, @v_time, @v_date1); ";
        $SetItemRec        .= "select @Final_date2 = datediff(s, @v_time, @v_date2); ";
        $SetItemRec        .= "EXEC WZ_GremoryCase_AddItem '".$Username."','".$Character_Name."',1,10,".$ItemFinalIndex.",".$ItemiLevel.",255,0,0,0,0,0,0,0,0,0,0,0,0,0,@Final_date1,@Final_date2";
        $ItemRecResult      =   $this->dB->query_fetch_single($SetItemRec);    
	}

    public function GenerarHexItem($Level,$Durabilidad,$Skill,$Luck,$Life,$ExeOP,$SetOP,$HHOP,$Op380,$Socket1,$Socket2,$Socket3,$Socket4,$Socket5,$Item_Group,$Item_Index){

        $Serial         =   $this->dB->query_fetch_single("exec WZ_GetItemSerial2");
        $SerialItem     =   $Serial["ItemSerial"];

        $LevelLifeSkillLuck         =   0;

        if ($Luck == 1) { $LevelLifeSkillLuck += 4;  }
        if ($Skill == 1) {  $LevelLifeSkillLuck += 128; }
        if (4 <= $Life) {  $LevelLifeSkillLuck += $Life - 4; } 
        else { $LevelLifeSkillLuck += $Life; }
        if (0 < $Level) {  $LevelLifeSkillLuck += $Level * 8; }

        if (256 <= $Item_Index) {
            $Item_Index = $Item_Index - 256;
        }

        $ItemHex = sprintf("%02X", $Item_Index, 0);
        $ItemHex .= sprintf("%02X", $LevelLifeSkillLuck, 0);
        $ItemHex .= sprintf("%02X", $Durabilidad, 0);
        $ItemHex .= sprintf("%08X", $SerialItem, 0);
        $ItemHex .= sprintf("%02X", $ExeOP, 0);
        $ItemHex .= sprintf("%02X", $SetOP, 0);
        $ItemHex .= dechex($Item_Group);
        if ($Op380 == 128) {
            $ItemHex .= "8";
        } else {
            $ItemHex .= "0";
        }
        $ItemHex .= sprintf("%02X", $HHOP, 0);
        $ItemHex .= sprintf("%02X", $Socket1, 0);
        $ItemHex .= sprintf("%02X", $Socket2, 0);
        $ItemHex .= sprintf("%02X", $Socket3, 0);
        $ItemHex .= sprintf("%02X", $Socket4, 0);
        $ItemHex .= sprintf("%02X", $Socket5, 0);
        $ItemHex = strtoupper($ItemHex);

        return $ItemHex;
    }

    public function InsertItemWarehouse($Usuario,$Level,$Durabilidad,$Skill,$Luck,$Life,$ExeOP,$SetOP,$HHOP,$Op380,$Socket1,$Socket2,$Socket3,$Socket4,$Socket5,$Item_Group,$Item_Index){
        $ItemHex            =   $this->GenerarHexItem($Level,$Durabilidad,$Skill,$Luck,$Life,$ExeOP,$SetOP,$HHOP,$Op380,$Socket1,$Socket2,$Socket3,$Socket4,$Socket5,$Item_Group,$Item_Index);
       if (!$this->common->accountOnline($Usuario)) {
            $Baul = $this->dB->query_fetch_single("SELECT CONVERT(VARCHAR(MAX), (SELECT Items FROM warehouse WHERE AccountID = ?), 2) AS Baul", [$Usuario]);
            $Baul = $Baul["Baul"];
            $ItemInfo = $this->ObtainItemInfo($Item_Group,$Item_Index);
            $test = 0;
            $slot = $this->SmartSearch($Usuario, $Baul, $ItemInfo["X"], $ItemInfo["Y"]);
            $test = $slot * 32;
            if ($slot == 1337) {
                message('error', '<b>[GIFT Code]</b> No hay espacio en tu baul para insertar el item de este codigo.');
            } else {
                $NuevoBaul = substr_replace($Baul, $ItemHex, $test, 32);
                $NuevoBaul = "0x" . $NuevoBaul;
                $update = $this->dB->query("UPDATE [warehouse] SET [Items] = " . $NuevoBaul . " WHERE [AccountID] = '" . $Usuario . "'");
            }
        } else {
            message('error', '<b>[GIFT Code]</b> La cuenta debe estar desconectada del juego.');
        }
    }

    public function ObtainItemInfo($Item_Group,$Item_Index){
        $result = $this->dB->query_fetch_single("SELECT * FROM WEBENGINE_GIFT_CODE_ITEMS WHERE iGrupo='".$Item_Group."' AND iIndex='".$Item_Index."'");
        if(!is_array($result)) return;
        return $result;
    }

    public function SmartSearch($username, $whbin, $itemX, $itemY)
    {
        if (substr($whbin, 0, 2) == "0x") {
            $whbin = substr($whbin, 2);
        }
        $items = str_repeat("0", 120);
        $itemsm = str_repeat("1", 120);
        $i = 0;
        while ($i < 120) {
            $_item = substr($whbin, 32 * $i, 32);
            $sy = hexdec(substr($_item, 0, 2));
            $ioo = hexdec(substr($_item, 14, 2));
            $type = hexdec(substr($_item, 18, 1));
            if (128 <= $ioo) {
                $sy = $sy + 256;
                $ioo -= 128;
            }
            $res = $this->ObtainItemInfo($type,$sy);
            $y = 0;
            while ($y < $res["Y"]) {
                $y++;
                $x = 0;
                while ($x < $res["X"]) {
                    $items = substr_replace($items, "1", $i + $x + ($y - 1) * 8, 1);
                    $x++;
                }
            }
            $i++;
        }
        $y = 0;
        while ($y < $itemY) {
            $y++;
            $x = 0;
            while ($x < $itemX) {
                $x++;
                $spacerq[$x + 8 * ($y - 1)] = true;
            }
        }
        $walked = 0;
        $i = 0;
        while ($i < 120) {
            if (isset($spacerq[$i])) {
                $itemsm = substr_replace($itemsm, "0", $i - 1, 1);
                $last = $i;
                $walked++;
            }
            if ($walked == count($spacerq)) {
                $i = 119;
            }
            $i++;
        }
        $useforlength = substr($itemsm, 0, $last);
        $findslotlikethis = "/^" . str_replace("1", "[01]", $useforlength) . "\$/i";
        $i = 0;
        $nx = 0;
        $ny = 0;
        while ($i < 120) {
            if ($nx == 8) {
                $ny++;
                $nx = 0;
            }
            if (preg_match($findslotlikethis, substr($items, $i, strlen($useforlength))) && $itemX + $nx < 9 && $itemY + $ny < 16) {
                return $i;
            }
            $i++;
            $nx++;
        }
        return 1337;
    }

}
?>