<?php

// Set error reporting to only show errors and parse errors
error_reporting(E_ERROR | E_PARSE);

// Set the time limit for script execution to unlimited
set_time_limit(-1);

// Set the maximum input time to unlimited
ini_set('max_input_time', '-1');

// Set the maximum execution time to unlimited
ini_set('max_execution_time', '0');

// Start the session
session_start();

// Start output buffering
ob_start();

// Define the constant 'DB_FILE' with the value of 'modname' session variable followed by ".db"
define('DB_FILE', $_SESSION['modname'] . ".db");

// Include the configuration file
require_once './config.php';

// Include the PDO wrapper file
require_once './_pdo.php';

// Include the required class files
require_once "./src/D2Functions.php";
require_once "./src/D2Database.php";
require_once './src/D2Files.php';
require_once './src/D2TxtParser.php';
require_once './src/D2ItemDesc.php';
require_once './src/D2Char.php';
require_once './src/D2CharStructureData.php';
require_once './src/D2ByteReader.php';
require_once './src/D2BitReader.php';
require_once './src/D2Item.php';
require_once './src/D2Char.php';

PDO_Connect("sqlite:" . DB_FILE);

// Create an instance of D2CharStructureData class
$csData = new D2CharStructureData();

$g = $_GET;
$cmd = $g['cmd'];

// Get the file path from the POST data and replace backslashes /
$filePath = $g['filePath'];
//$filePath = str_replace("\\", "\\\\", $filePath);

$cmd = $_GET['cmd'];
$name = $_GET['name'];
$value = $_GET['value'];

$char = new D2Char(basename($filePath));

switch ($cmd) {
    case "CharacterName":
        // Handle CharacterName command
        // Validate the character name length
        if (strlen($value) < 2 || strlen($value) > 15) {
            echo "Character name must be between 2 and 15 characters long.";
            // You can handle the error case accordingly (e.g., return an error response)
            // Additional validation checks can be added here as needed
        } else {
            // Validate the character name format
            $pattern = '/^[A-Za-z0-9_-]+$/'; // Regular expression pattern for allowed characters
            if (!preg_match($pattern, $value)) {
                echo "\nCharacter name contains invalid characters. Only alphabets, numbers, underscore, and dash are allowed.";
                // Handle the error case accordingly
            } else {
                // The character name is valid, proceed with further processing
                $char->setChar($cmd, $value);
                echo "\nCharacter Name and filename Changed";
            }
        }
        echo "\nHandling CharacterName command - Name: $value, File Path: $filePath";
        break;
    case "CharacterClass":
        // Handle CharacterClass command
        $char->setChar($cmd, $value);
        echo "Handling CharacterClass command - Class: $value, File Path: $filePath";
        break;
    case "CharacterLevel":
        // Handle CharacterLevel command
        $char->setChar($cmd, $value);
        echo "Handling CharacterLevel command - Level: $value, File Path: $filePath";
        break;

    // handle difficulty wierdly
    case "Normal":
        $char->setChar("CharacterProgression", $value);
        echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
        break;
    case "Finished Normal":
        $char->setChar("CharacterProgression", $value);
        echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
        break;
    case "Finished Nightmare":
        $char->setChar("CharacterProgression", $value);
        echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
        break;
    case "Finished Hell":
        $char->setChar("CharacterProgression", $value);
        echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
        break;
    // skills
    case "skills":
        //var_dump($char->cData);
        $char->setSkill($name, $value);
        echo "Handling skills command - Skill: $name, Value: $value, File Path: $filePath";
        break;

    case "Died":
        $char->setChar("CharacterStatus", "Died", $value); // Set the "CharacterStatusDied" value to the provided value
        echo "Handling Died command - Value: $value, File Path: $filePath"; // Display a message indicating the handling of the Died command
        break;

    case "Expansion":
        $char->setChar("CharacterStatus", "Expansion", $value); // Set the "CharacterStatusExpansion" value to the provided value
        echo "Handling Expansion command - Value: $value, File Path: $filePath"; // Display a message indicating the handling of the Expansion command
        break;

    case "Hardcore":
        $char->setChar("CharacterStatus", "Hardcore", $value); // Set the "CharacterStatusHardcore" value to the provided value
        echo "Handling Hardcore command - Value: $value, File Path: $filePath"; // Display a message indicating the handling of the Hardcore command
        break;

// Handle the WP check/uncheck
    case "wp":
        $diff = $g['diff'];

        if ($diff == "Norm") {
            $offset = 643;
        }

        if ($diff == "NM") {
            $offset = 667;
        }

        if ($diff == "Hell") {
            $offset = 691;
        }

        /*
          array (size=5)
          'cmd' => string 'wp' (length=2)
          'name' => string '1' (length=1)
          'value' => string '1' (length=1)
          'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48)
          'diff' => string 'Norm' (length=4)
         */

        $fileContents = file_get_contents($filePath); // Read the contents of the file
        $ByteReader = new D2ByteReader($fileContents); // Create a new instance of D2ByteReader with the file data
        $fileData = $ByteReader->getData(); // Get the data from the ByteReader instance

        $wpBytes = $ByteReader->read($offset, 5, 1);
        $wpBytesToBits = $ByteReader->toBits($wpBytes);

        $BitReader = new D2BitReader($wpBytesToBits);
        $BitReader->setBit($g['name'], $g['value']);

        $newBits = $BitReader->getBits();
        $newBitsToBytes = $ByteReader->bitsToHexString($newBits);

        $ByteReader->writeBytes($offset, $newBitsToBytes);
        $newFileData = $ByteReader->getData();
        $fileSaved = file_put_contents($filePath, $newFileData);
        $checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));

        if ($fileSaved) {
            echo "Success";
        } else {
            echo "Fail";
        }
        break;

    /*
     * array (size=5)
      'cmd' => string 'q' (length=1)
      'name' => string 'Sisters_Burial_Grounds' (length=29)
      'value' => string '1' (length=1)
      'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48)
      'diff' => string 'Norm' (length=4)

      At each quest offset, read a short, 2 bytes.
      347 => 'Den_Of_Evil',
      349 => 'Sisters_Burial_Grounds',
      351 => 'Tools_Of_The_Trade',
      353 => 'The_Search_For_Cain',
      355 => 'The_Forgotten_Tower',
      357 => 'Sisters_To_The_Slaughter',

      Each short is 16 bytes.
     *
     * 0xFEFF = 11111110 11111111
     * Short #0	Den of Evil	Bit 4 is set when you enter the Den.

     */

    case "q":
        $diff = $g['diff'];
        if ($diff == "Norm") {
            $qArray = array_flip($csData->qNorm);
            $questOffset = $qArray[$g['name']];
        }

        if ($diff == "NM") {
            $qArray = array_flip($csData->qNM);
            $questOffset = $qArray[$g['name']];
        }

        if ($diff == "Hell") {
            $qArray = array_flip($csData->qHell);
            $questOffset = $qArray[$g['name']];
        }

        // Open the file in binary mode for both reading and writing
        $fp = fopen($filePath, "rb+");

        if ($g['value']) {
            // Set the file pointer position to the quest offset
            fseek($fp, $questOffset);

            // Write the byte value 0xFE at the current position
            fwrite($fp, pack('C', 0xFE));

            // Move the file pointer to the next position
            fseek($fp, $questOffset + 1);

            // Write the byte value 0xFF at the current position
            fwrite($fp, pack('C', 0xFF));

            echo "Quest Just Finished, Collect Reward!";
        } else {
            // Set the file pointer position to the quest offset
            fseek($fp, $questOffset);

            // Write the byte value 0xFE at the current position
            fwrite($fp, pack('C', 0x00));

            // Move the file pointer to the next position
            fseek($fp, $questOffset + 1);

            // Write the byte value 0xFF at the current position
            fwrite($fp, pack('C', 0x00));

            echo "Quest Not Started Yet!";
        }

        $checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
        fclose($fp);
        break;

    // stats commands
    case "stats":
        echo "Handling $name command. New value: $value";
        $char->setStat($name, $value);
        break;

    // setallskills
    case "setallskills":
        echo "Handling $name command. New value: $value";
        $char->setAllSkills($value);
        break;

    // q_all
    case "q_all":
        echo "Handling $name command. New value: $value";
        $fp = fopen($filePath, "rb+");
        $offsets = array_merge(array_keys($csData->qNorm), array_keys($csData->qNM), array_keys($csData->qHell));

        $packValue1 = ($value == 1) ? 0xFE : 0x00;
        $packValue2 = ($value == 1) ? 0xFF : 0x00;
        foreach ($offsets as $k => $v) {
            fseek($fp, $v);
            fwrite($fp, pack('C', $packValue1));
            fseek($fp, $v + 1);
            fwrite($fp, pack('C', $packValue2));
        }

        $checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
        break;

    // wp_all
    case "wp_all":
        echo "Handling $name command. New value: $value";
        $fp = fopen($filePath, "rb+");

        // Determine the pack value based on the $value variable
        $packValue = ($value == 1) ? 0xFF : 0x00;

        // Define the WP offsets
        $wp_offsets = [
            643, 644, 645, 646, 647, // Norm
            667, 668, 669, 670, 671, // NM
            691, 692, 693, 694, 695   // Hell
        ];

        // Iterate over the WP offsets
        foreach ($wp_offsets as $offset) {
            fseek($fp, $offset);
            fwrite($fp, pack('C', $packValue));
        }

        $checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
        break;

    // default command
    default:
        // Handle unknown command
        echo "Unknown command: $cmd";
        break;
}