<?php
setlocale(LC_ALL, 'de_DE.UTF-8');

function err($code, $msg) {
    header('Content-Type: application/json');
    echo json_encode(['error' => ['code' => intval($code), 'msg' => $msg]]);
    exit;
}

function toBytes($val) {
    $val = trim($val);
    $last = strtolower($val[strlen($val)-1]);
    $val = (int)$val;
    switch ($last) {
        case 'g': $val *= 1024 ** 3; break;
        case 'm': $val *= 1024 ** 2; break;
        case 'k': $val *= 1024; break;
    }
    return $val;
}

$uploadDir = __DIR__ . '/img/';
$gpxDir    = __DIR__ . '/gpx/';
$minDir    = __DIR__ . '/min/';

if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);
if (!is_dir($gpxDir)) mkdir($gpxDir, 0755, true);
if (!is_dir($minDir)) mkdir($minDir, 0755, true);

if (!isset($_COOKIE['_sfm_xsrf'])) {
    setcookie('_sfm_xsrf', bin2hex(random_bytes(16)));
}

if (isset($_FILES['file_data'])) {
    if (!isset($_POST['xsrf']) || $_POST['xsrf'] !== $_COOKIE['_sfm_xsrf']) {
        err(403, 'Invalid XSRF token');
    }

    $fileName = $_FILES['file_data']['name'];
    $fileTmp = $_FILES['file_data']['tmp_name'];
    $allowedExtensions = ['jpg', 'jpeg', 'png', 'gpx'];
    $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

    if (!in_array($ext, $allowedExtensions)) {
        err(400, 'File extension not allowed');
    }

    $folder = $_POST['folder'] ?? 'img';
    $allowedFolders = ['img', 'gpx', 'min'];
    if (!in_array($folder, $allowedFolders)) $folder = 'img';

    $targetDir = __DIR__ . "/$folder/";
    $targetPath = $targetDir . basename($fileName);

    $maxUploadBytes = min(toBytes(ini_get('post_max_size')), toBytes(ini_get('upload_max_filesize')));
    if ($_FILES['file_data']['size'] > $maxUploadBytes) {
        err(400, 'File too large');
    }

    if (!move_uploaded_file($fileTmp, $targetPath)) {
        err(500, 'Error while saving');
    }

    if ($folder === 'img') {
        processImage($fileName);
    }

    header('Content-Type: application/json');
    echo json_encode(['success' => true, 'file' => $fileName]);
    exit;
}

if (isset($_POST['action']) && $_POST['action'] === 'update_thumbnails') {
    header('Content-Type: application/json');
    echo json_encode(processAllImages());
    exit;
}

function processAllImages() {
    $sourceDir = __DIR__ . '/img';
    $response = ['success' => true, 'count' => 0, 'errors' => []];
    if (!is_dir($sourceDir)) return ['success' => false, 'error' => 'Ordner fehlt'];

    $files = scandir($sourceDir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        if (is_file($sourceDir . '/' . $file)) {
            $result = processImage($file);
            if ($result['success']) {
                $response['count']++;
            } else {
                $response['errors'][] = $file;
            }
        }
    }
    return $response;
}

function processImage($fileName) {
    $sourcePath = __DIR__ . '/img/' . $fileName;
    $destPath = __DIR__ . '/min/' . $fileName;
    $targetWidth = 100;

    if (!class_exists('Imagick')) return ['success' => false, 'error' => 'Imagick fehlt'];
    if (!file_exists($sourcePath)) return ['success' => false, 'error' => 'Datei fehlt'];

    try {
        $img = new Imagick($sourcePath);
        $img->autoOrient();
        $width = $img->getImageWidth();
        if ($width > $targetWidth) {
            $newHeight = (int) round($img->getImageHeight() * ($targetWidth / $width));
            $img->resizeImage($targetWidth, $newHeight, Imagick::FILTER_LANCZOS, 1);
        }
        if (strtolower($img->getImageFormat()) === 'jpeg') {
            $img->setImageCompressionQuality(90);
        }
        $img->writeImage($destPath);
        $img->clear();
        $img->destroy();
        return ['success' => true];
    } catch (Exception $e) {
        return ['success' => false, 'error' => $e->getMessage()];
    }
}
?>
<!DOCTYPE html>
<html lang="de">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Upload</title>

<style>
  /* Grundlegendes Fix für alle Elemente */
  * {
    box-sizing: border-box;
  }

  body {
    font-family: Arial, sans-serif;
    padding: 15px;
    margin: 0;
    background: #f9f9f9;
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow-x: hidden; /* Verhindert seitliches Scrollen */
  }

  /* Container auf 90% begrenzen, aber maximal 600px */
  .button-container, 
  .info-list-container, 
  #status_message, 
  #prefix_container, 
  #file_drop_target, 
  #upload_progress {
    width: 90%;
    max-width: 600px;
    margin-bottom: 15px;
  }

.button-container {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px; 
    flex-wrap: nowrap; 
    width: 100%; 
  }

.button {
    font-size: 1.1em;
    font-weight: bold;
    border: none;
    border-radius: 6px;
    padding: 10px 15px;
    cursor: pointer;
    text-decoration: none;
    text-align: center;
    color: white;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    
    flex: 1 1 0px; 
    min-width: 80px;
    white-space: normal;
    line-height: 1.2;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  #mapBtn { background: linear-gradient(90deg, #e74c3c 0%, #c0392b 100%); }
  #updateBtn { background: linear-gradient(90deg, #3498db 0%, #217dbb 100%); }

  .upload-label {
    font-size: 1.2em;
    font-weight: bold;
    color: #999;
    letter-spacing: 1px;
    text-transform: uppercase;
    text-align: center;
  }

  /* Info Liste: Automatisch 1 oder 2 Spalten */
  .info-list {
    margin: 0;
    padding-left: 18px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 5px 15px;
  }

  .info-list li {
    color: #666;
    font-size: 0.85em;
    line-height: 1.3;
  }

  #filename_prefix {
    width: 100%;
    padding: 12px;
    border: 2px solid #ddd;
    border-radius: 6px;
    font-size: 1.1em;
  }

  #file_drop_target {
    min-height: 160px;
    padding: 30px 15px;
    border: 4px dashed #222;
    background: white;
    border-radius: 6px;
    font-size: 1.2em;
    font-weight: bold;
    text-align: center;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  #file_drop_target.dragover {
    border-color: #3498db;
    color: #3498db;
  }

  /* Status Meldungen */
  #status_message {
    padding: 10px;
    border-radius: 6px;
    text-align: center;
    font-weight: bold;
    display: none;
  }

  .status-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
  .status-error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }

  /* Upload Einträge */
  .upload-entry {
    background: white;
    padding: 10px;
    margin: 5px 0;
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  }

  .upload-progress {
    height: 8px;
    background: #eee;
    border-radius: 4px;
    overflow: hidden;
  }

  .progress-bar {
    height: 100%;
    background: #3498db;
    width: 0%;
    transition: width 0.3s;
  }
  
  .upload-status {
  display: flex;
  justify-content: space-between; 
  width: 100%;
  margin-bottom: 5px;
  font-size: 0.9em;
}

.status-text {
  text-align: right;
  font-weight: bold;
}
  
</style>


   </head>
   <body>
         <div class="button-container">
         <a href="./" class="button" id="mapBtn">Main page</a>
         <span class="upload-label">Upload</span>
         <button type="button" class="button" id="updateBtn">New Thumbnails</button>
      </div>
      
      
      
      <div id="status_message"></div>
      <div id="prefix_container">
         <input type="text" id="filename_prefix" placeholder="File prefix for uploads...">
      </div>
      <div id="file_drop_target" tabindex="0">Click or drag files here to upload</div>
      <input type="file" id="file_input" multiple style="display:none;" accept=".jpg,.jpeg,.png,.gpx">
      <div id="upload_progress"></div>
      
      
      
   <div class="info-list-container">
<ul class="info-list">
    <li><strong>Smart Resizing:</strong> All images are saved to <span class="folder-label">img/</span>, large files resized to a width of 500px - 999px.</li>
    <li><strong>Automatic Thumbnails:</strong> 100px previews are generated instantly to <span class="folder-label">min/</span>.</li>
    <li><strong>GPX Storage:</strong> GPS track files are automatically moved to <span class="folder-label">gpx/</span>.</li>
    <li><strong>GPS Data:</strong> All EXIF and location metadata are preserved during the process.</li>
    <li><strong>Organization:</strong> You can add a custom prefix to group your uploaded files.</li>
    <li><strong>Manual Processing:</strong> If you upload images directly to <span class="folder-label">img/</span>, use the <strong>"New Thumbnails"</strong> button to generate thumbnails manually.</li>

    <li><strong>Pica:</strong> High-quality image resizing <a href="https://github.com/nodeca/pica" target="_blank" style="color: #999;">(MIT License)</a></li>
    <li><strong>Piexifjs:</strong> GPS/EXIF metadata handling <a href="https://github.com/hMatoba/piexifjs" target="_blank" style="color: #999;">(MIT License)</a></li>

</ul>
</div>      
      
      
      <script src="../js/pica.min.js"></script>
      <script src="../js/piexifjs.js"></script>
      <script>
         const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gpx'];
         const MAX_UPLOAD_SIZE = 100 * 1024 * 1024;
         const XSRF = (document.cookie.match('(^|; )_sfm_xsrf=([^;]*)') || [])[2];
         

         function showStatus(text, isSuccess = true) {
             const statusDiv = document.getElementById('status_message');
             statusDiv.textContent = text;
             statusDiv.className = isSuccess ? 'status-success' : 'status-error';
             statusDiv.style.display = 'block';
             

             setTimeout(() => { statusDiv.style.display = 'none'; }, 5000);
         }
         
         document.getElementById('updateBtn').addEventListener('click', () => {
             const statusDiv = document.getElementById('status_message');
             showStatus('Processing images...', true);
             
             const formData = new FormData();
             formData.append('action', 'update_thumbnails');
             formData.append('xsrf', XSRF);
             
             fetch(window.location.href, { method: 'POST', body: formData })
             .then(r => r.json())
             .then(data => {
                 if(data.success) {
                     showStatus(`Success! ${data.count} thumbnails updated.`, true);
                 } else {
                     showStatus('Error during update: ' + (data.error || 'Unknown'), false);
                 }
             })
             .catch(() => showStatus('Network error', false));
         });
         
         document.getElementById('file_drop_target').addEventListener('click', () => document.getElementById('file_input').click());
         document.getElementById('file_drop_target').addEventListener('dragover', e => { e.preventDefault(); e.target.classList.add('dragover'); });
         document.getElementById('file_drop_target').addEventListener('dragleave', e => e.target.classList.remove('dragover'));
         document.getElementById('file_drop_target').addEventListener('drop', e => { e.preventDefault(); e.target.classList.remove('dragover'); handleFiles(e.dataTransfer.files); });
         document.getElementById('file_input').addEventListener('change', e => handleFiles(e.target.files));
         
         function handleFiles(files) {
             const rawPrefix = document.getElementById('filename_prefix').value.trim();
             const prefix = rawPrefix.replace(/[^a-z0-9_-]/gi, '_');
         
             Array.from(files).forEach(file => {
                 const ext = file.name.split('.').pop().toLowerCase();
                 if (!ALLOWED_EXTENSIONS.includes(ext) || file.size > MAX_UPLOAD_SIZE) return;
         
                 const newName = prefix ? `${prefix}_${file.name}` : file.name;
                 const renamedFile = new File([file], newName, { type: file.type });
                 const entry = createUploadEntry(renamedFile);
         
                 if (ext === 'gpx') {
                     uploadFile(renamedFile, entry, 'gpx');
                 } else {
                     resizeAndUpload(renamedFile, entry);
                 }
             });
         }
         
         function createUploadEntry(file) {
             const entry = document.createElement('div');
             entry.className = 'upload-entry';
             entry.innerHTML = `<div class="upload-status"><span>${file.name}</span><span class="status-text">0%</span></div>
                                <div class="upload-progress"><div class="progress-bar"></div></div>`;
             document.getElementById('upload_progress').appendChild(entry);
             return entry;
         }
         
         async function resizeAndUpload(file, entry) {
             try {
                 const resized = await resizeImage(file);
                 await uploadFile(resized, entry, 'img');
             } catch (e) {
                 entry.querySelector('.status-text').textContent = 'Error';
             }
         }
         
         function uploadFile(file, entry, folder) {
             return new Promise((resolve, reject) => {
                 const formData = new FormData();
                 formData.append('file_data', file);
                 formData.append('folder', folder);
                 formData.append('xsrf', XSRF);
         
                 const xhr = new XMLHttpRequest();
                 xhr.open('POST', window.location.href);
                 xhr.upload.onprogress = e => {
                     if (e.lengthComputable) {
                         const p = Math.round((e.loaded / e.total) * 100);
                         entry.querySelector('.progress-bar').style.width = p + '%';
                         entry.querySelector('.status-text').textContent = p + '%';
                     }
                 };
xhr.onload = () => {
            try {
                const res = JSON.parse(xhr.responseText);
                const statusElem = entry.querySelector('.status-text');
                const progressBar = entry.querySelector('.progress-bar');
                
                if (res.success) {
                    statusElem.textContent = 'Done';
                    statusElem.style.color = '#2ecc71';
                    progressBar.style.backgroundColor = '#2ecc71';
                } else {
                    statusElem.textContent = 'Error';
                    statusElem.style.color = '#e74c3c';
                    progressBar.style.backgroundColor = '#e74c3c';
                }
            } catch(e) {
                const statusElem = entry.querySelector('.status-text');
                const progressBar = entry.querySelector('.progress-bar');
                statusElem.textContent = 'Error';
                statusElem.style.color = '#e74c3c';
                progressBar.style.backgroundColor = '#e74c3c';
            }
            resolve();
        };
                 xhr.onerror = reject;
                 xhr.send(formData);
             });
         }
         
         async function resizeImage(file) {
             const LIMIT = 500;
             const picaInstance = pica();
             
             return new Promise((resolve, reject) => {
                 const reader = new FileReader();
                 reader.onload = e => {
                     const originalDataURL = e.target.result;
                     let exif;
                     
                     try {
                         exif = piexif.load(originalDataURL);
                     } catch (err) {
                         console.warn("Keine EXIF-Daten gefunden");
                     }
         
                     const img = new Image();
                     img.onload = async () => {
                         let currentW = img.width;
                         let currentH = img.height;
         
                         while (currentW / 2 >= LIMIT) {
                             currentW = Math.round(currentW / 2);
                             currentH = Math.round(currentH / 2);
                         }
         
                         const canvas = document.createElement('canvas');
                         canvas.width = currentW;
                         canvas.height = currentH;
         
                         await picaInstance.resize(img, canvas, {
                             unsharpAmount: 80,
                             unsharpRadius: 0.6,
                             unsharpThreshold: 2
                         });
                         
                         canvas.toBlob(async blob => {
                             const r2 = new FileReader();
                             r2.onload = e2 => {
                                 let finalData = e2.target.result;
                                 if (exif) {
                                     try {
                                         const exifStr = piexif.dump(exif);
                                         finalData = piexif.insert(exifStr, e2.target.result);
                                     } catch (insertErr) {
                                         console.error("Error during GPS-Re-Insert:", insertErr);
                                     }
                                 }
                                 const finalBlob = dataURLtoBlob(finalData);
                                 resolve(new File([finalBlob], file.name, { type: 'image/jpeg' }));
                             };
                             r2.readAsDataURL(blob);
                         }, 'image/jpeg', 0.90);
                     };
                     img.src = originalDataURL;
                 };
                 reader.readAsDataURL(file);
             });
         }
         
         
         
         function dataURLtoBlob(url) {
             const parts = url.split(','), mime = parts[0].match(/:(.*?);/)[1], b = atob(parts[1]);
             let n = b.length, u = new Uint8Array(n);
             while(n--) u[n] = b.charCodeAt(n);
             return new Blob([u], {type: mime});
         }
      </script>
   </body>
</html>
