<?php
/*
 *
 * Copyright (C) 2024 Joakim Tufvegren
 *
 * This script is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This script is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * The GNU Affero General Public License can be found at
 * <http://www.gnu.org/licenses/>.
 *
 */

///////////////////////////////////////////////////////////////////////////////
// Global variables
///////////////////////////////////////////////////////////////////////////////
$public_links = array('ip' => array('/ip/''minimalistic page that shows your IP, hostname and user agent'),
                      
'pactrack_droid' => array('/pactrackdroid/''an Android app I made (in Swedish only)'),
                      
'mouse_rally' => array('/mouserally/''a game I made (in Swedish only)'),
                      
'files' => array('/files/''miscellaneous files'));
$protected_links = array('secure_files' => array('/secure/''password protected files'));
$googapps_links = array('mail''calendar''drive');

$languages = array('rubyCode' => 'menu.rb',
                   
'javaCode' => 'Menu.java',
                   
'phpCode' => 'menu.php');

///////////////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////////////
function camelCase($text) {
  return 
preg_replace_callback('/(\w*)_(\w)(\w*)/U',
                               function (
$matches) {
                                 return 
$matches[1].strtoupper($matches[2]).$matches[3];
                               },
                               
$text);
}

function 
rubyCode() {
  global 
$public_links$protected_links$googapps_links;

  
$code = <<<HEAD
module Firetech

  # The Menu class provides a Multiple Entry Navigation Utility (M.E.N.U.)
  class Menu
HEAD;
  
$code .= "\n\n";
  foreach (
$public_links as $name => $info) {
    
$code .= "    def <a href=\"{$info[0]}\">$name</a>; <span class=\"comment\">'{$info[1]}'</span>; end\n";
  }
  
$code .= "\n";
  
$code .= "    protected\n";
  foreach (
$protected_links as $name => $info) {
    
$code .= "      def <a href=\"{$info[0]}\">$name</a>; <span class=\"comment\">'{$info[1]}'</span>; end\n";
  }
  
$code .= "\n";
  
$code .= "    private\n";
  foreach (
$googapps_links as $link) {
    
$code .= "      def <a href=\"http://$link.firetech.nu\">$link</a>; <span class=\"comment\">'Google " ucfirst($link) . "'</span>; end\n";
  }
  
$code .= "\n";
  
$code .= <<<FOOT
  end

end

puts "Use the <a href="index.phps">source</a>..."
FOOT;

  return 
$code;
}

function 
javaCode() {
  global 
$public_links$protected_links$googapps_links;

  
$code = <<<HEAD
package nu.firetech;

import java.net.URL;

/**
 * The &lt;code&gt;Menu&lt;/code&gt; class provides a
 * Multiple Entry Navigation Utility (M.E.N.U.)
 */
public class Menu {
HEAD;
  
$code .= "\n";
  foreach (array(
'public''protected') as $class) {
    
$varName "{$class}_links";
    foreach ($
$varName as $name => $info) {
      
$code .= "    $class URL <a href=\"{$info[0]}\">" camelCase($name) . "</a>;&nbsp;<span class=\"comment\">//{$info[1]}</span>\n";
    }
    
$code .= "\n";
  }
  foreach (
$googapps_links as $link) {
    
$code .= "    private URL <a href=\"http://$link.firetech.nu\">$link</a>;&nbsp;<span class=\"comment\">//Google " ucfirst($link) . "</span>\n";
  }
  
$code .= "\n";
  
$code .= <<<FOOT
    public static void main(String[] args) {
        System.out.println("Use the <a href="index.phps">source</a>...");
    }
}
FOOT;

  return 
$code;
}

function 
phpCode() {
  global 
$public_links$protected_links$googapps_links;

  
$code = <<<HEAD
&lt;?php

/**
 * The Menu class provides a Multiple Entry Navigation Utility (M.E.N.U.)
 */
class Menu {
HEAD;
  
$code .= "\n";
  foreach (array(
'public''protected') as $class) {
    
$varName "{$class}_links";
    foreach ($
$varName as $name => $info) {
      
$code .= "    $class $<a href=\"{$info[0]}\">" camelCase($name) . "</a>;&nbsp;<span class=\"comment\">//{$info[1]}</span>\n";
    }
    
$code .= "\n";
  }
  foreach (
$googapps_links as $link) {
    
$code .= "    private $<a href=\"http://$link.firetech.nu\">$link</a>;&nbsp;<span class=\"comment\">//Google " ucfirst($link) . "</span>\n";
  }
  
$code .= <<<FOOT
}

print("Use the <a href="index.phps">source</a>...");

?>
FOOT;

  return 
$code;
}

///////////////////////////////////////////////////////////////////////////////
// Preparation of M.E.N.U.
///////////////////////////////////////////////////////////////////////////////
$getLang = (isset($_GET['lang']) ? strtolower($_GET['lang']) . 'Code' '');
$lang = (in_array($getLangarray_keys($languages)) ? $getLang array_rand($languages));
$fileName $languages[$lang];
$menu $lang();

$menu preg_replace('/^ /m''&nbsp;'str_replace('  ''&nbsp; 'nl2br($menu)));

$cleanMenu html_entity_decode(strip_tags($menu), ENT_COMPAT);
$menuLines count(explode("\n",$cleanMenu));
$menuChars strlen($cleanMenu) + 1;
$lastLineLength strlen(preg_replace("/.*\n/"''$cleanMenu));
$fillerLines str_repeat("~<br/>\n"50);

$statusWritten "\"$fileName\" {$menuLines}L, {$menuChars}C written";
$statusRuler "$menuLines,$lastLineLength";

$menu substr($menu0, -1) . '<span id="caret" class="caret1">' substr($menu, -1) . "</span><br/>";

$langKeys array_keys($languages);
$langPos array_search($lang$langKeys);
$prevLang $langKeys[($langPos $langPos count($langKeys) - 1)];
$nextLang $langKeys[($langPos count($langKeys) - $langPos 0)];

$tabs '';
foreach (
$languages as $tabLang => $tabLangFile) {
  if (
$tabLang == $prevLang) {
    
$id ' id="prevlang"';
  } elseif (
$tabLang == $nextLang) {
    
$id ' id="nextlang"';
  } else {
    
$id '';
  }
  
$tabLangShort substr($tabLang0, -4);
  
$tabs .= "<a$id class=\"tab" . ($lang == $tabLang ' selected' '') . "\" href=\"?lang=$tabLangShort\" onclick=\"location.hash = '#$tabLangShort'; checkHash(); return false;\">$tabLangFile</a>";
}

$langShort substr($lang0, -4);

if (isset(
$_GET['xhr'])) {
///////////////////////////////////////////////////////////////////////////////
// Output JSON data for AJAX-based tab change
///////////////////////////////////////////////////////////////////////////////

  
print json_encode([
    
'tabs' => $tabs,
    
'menu' => $menu,
    
'fileName' => $fileName,
    
'statusWritten' => $statusWritten,
    
'ruler' => $ruler,
    
'langShort' => $langShort
  
]);

} else {
///////////////////////////////////////////////////////////////////////////////
// Output the actual page
///////////////////////////////////////////////////////////////////////////////
  
print <<<PAGE
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>firetech.nu</title>
<link rel="shortcut icon" href="/favicon.ico"/>
<script type="text/javascript">
<!--
var currentHash = (location.hash ? location.hash : '#
$langShort');
var loading = false;
var desiredUrl = baseUrl() + currentHash;
if (location.href != desiredUrl) {
  loading = (location.href != baseUrl());
  location.href = desiredUrl;
} else if (location.hash && location.hash != '#
$langShort') {
  ajaxTab();
}
function checkHash() {
  if (!loading && currentHash != location.hash) {
    currentHash = location.hash;
    ajaxTab();
  }
}
function baseUrl() {
  var pos = location.href.indexOf('?');
  if (pos == -1) {
    pos = location.href.indexOf('#');
  }
  if (pos == -1) {
    pos = location.href.length;
  }
  return location.href.substring(0, pos);
}
function ajaxTab() {
  if (!window.XMLHttpRequest) {
    return false;
  }
  var tab = currentHash.substring(1);
  var xhr = new XMLHttpRequest()
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status==200) {
      var data = JSON.parse(xhr.responseText);
      document.getElementById('tabs').innerHTML = data.tabs;
      document.getElementById('menu').innerHTML = data.menu;
      document.getElementById('filename').innerHTML = data.fileName;
      document.getElementById('written').innerHTML = data.statusWritten;
      document.getElementById('rulercontent').innerHTML = data.ruler;
      exitCommand();
      location.hash = currentHash = '#' + data.langShort;
      loading = false;
      gPressed = false;
    }
  }
  loading = true;
  xhr.open('GET', baseUrl() + '?lang=' + tab + '&xhr', true);
  xhr.send(null);
  return true;
}

var caret;
var caretState = 1;
var caretTimer = 0;
function blinkCaret() {
  caretState = 1 - caretState;
  if (caret) caret.className = 'caret' + caretState;
}

var moveElem;
var terminal;
var contents;
var resizing = 0;
var x = 0;
var y = 0;
function shadeTerminal() {
  var display = (contents.style.display == 'none' ? 'block' : 'none');
  contents.style.display = display;
  document.getElementById('dragbar').style.display = display;
}
function closeTerminal() {
  clearInterval(caretTimer);
  terminal.id = null;
  terminal.style.position = 'static';
  terminal.style.width = '640px';
  terminal.style.height = '50px';
  terminal.style.fontStyle = 'italic';
  terminal.style.textAlign = 'center';
  terminal.style.marginTop = '100px';
  terminal.innerHTML = 'Reload the page to get the M.E.N.U. back.<br/>Thanks for visiting firetech.nu!';
  return false;
}
function setMouseCommon(e) {
  if (e.which) {
    if (e.which != 1) return false;
  } else {
    if (e.button != 1) return false;
  }
  if (e.layerX) {
    var offset = (navigator.userAgent.indexOf('Firefox') != -1 ? 1 : 0);
    x = e.layerX + offset;
    y = e.layerY + offset;
  } else if (e.offsetX) {
    x = e.offsetX;
    y = e.offsetY;
    var o =  e.srcElement;
    while(o && o != terminal) {
      x += o.offsetLeft + 2;
      y += o.offsetTop;
      o = o.offsetParent;
    }
    if (!window.opera) {
      x += 2;
      y += 3;
    }
  }
  return true;
}
function startMove(e, elem) {
  if (!e) e = window.event;
  if (e.preventDefault) e.preventDefault();
  if (!setMouseCommon(e)) return true;
  moveElem = elem;
  document.onmousemove = mouseMove;
  document.getElementById('body').style.cursor = 'move';
  return false;
}
function mouseMove(e) {
  if (!e) e = window.event;
  moveElem.style.position = 'absolute';
  moveElem.style.left = (e.clientX - x) + 'px';
  moveElem.style.top = (e.clientY - y) + 'px';
  return false;
}
function startResizeLeft(e) {
  if (!e) e = window.event;
  if (e.preventDefault) e.preventDefault();
  if (!setMouseCommon(e)) return true;
  terminal.style.position = 'absolute';
  terminal.style.top = (e.clientY - y - (!e.layerX ? 3 : 0)) + 'px';
  x = new Array(terminal.offsetLeft + terminal.scrollWidth + x, x + 2);
  y = terminal.offsetTop - (terminal.scrollHeight - y) + 11;
  resizing = 1;
  document.onmousemove = mouseResize;
  document.getElementById('body').style.cursor = 'sw-resize';
  return false;
}
function startResizeMiddle(e) {
  if (!e) e = window.event;
  if (e.preventDefault) e.preventDefault();
  if (!setMouseCommon(e)) return true;
  y = terminal.offsetTop - (terminal.scrollHeight - y) + 11;
  resizing = 2;
  document.onmousemove = mouseResize;
  document.getElementById('body').style.cursor = 's-resize';
  return false;
}
function startResizeRight(e) {
  if (!e) e = window.event;
  if (e.preventDefault) e.preventDefault();
  if (!setMouseCommon(e)) return true;
  x = terminal.offsetLeft - (terminal.scrollWidth - x) + 2;
  y = terminal.offsetTop - (terminal.scrollHeight - y) + 11;
  resizing = 3;
  document.onmousemove = mouseResize;
  document.getElementById('body').style.cursor = 'se-resize';
  return false;
}
function mouseResize(e) {
  if (!e) e = window.event;
  if (resizing == 1) {
    var width = x[0] - e.clientX;
    if (width >= 640) {
      terminal.style.left = (e.clientX - x[1]) + 'px';
      terminal.style.width = width + 'px';
    }
  } else if (resizing == 3) {
    var width =  Math.max(e.clientX - x, 640);
    terminal.style.width = width + 'px';
  }
  var height =  Math.max(e.clientY - 22 - y, 450);
  contents.style.height = height + 'px';
  return false;
}

var gPressed = false;
var command = false;
var allowBackspaceClose = true;
function keyPress(e) {
  var key;
  e = e || window.event;

  if (document.layers) {
    key = e.which;
  } else if (document.all) {
    key = event.keyCode;
  } else if (document.getElementById) {
    key = e.keyCode;
  } else {
    return;
  }

  if (!command) {
    if (key == 71 && !e.shiftKey) {
      gPressed = !gPressed;
    } else if (key == 84 && gPressed) {
      document.getElementById((e.shiftKey ? 'prev' : 'next') + 'lang').onclick();
    } else if (key == 186 || key == 59 || (key == 190 && e.shiftKey)) {
      command = true;
      allowBackspaceClose = true;
      if (caret) caret.className = 'caret0';
      caret = document.getElementById('cmdCaret');
      if (caret) caret.className = 'caret1';
      caretState = 1;
      document.getElementById('command').style.display = 'block';
      document.getElementById('commandEdit').value = document.getElementById('commandContent').innerHTML = '';
      document.getElementById('written').style.display = 'none';
      document.getElementById('ruler').style.display = 'none';
      document.getElementById('commandEdit').focus();
    }
  } else {
    var text = document.getElementById('commandEdit').value;
    if (key == 27 || key == 13 || (key == 8 && text.length == 0 && allowBackspaceClose)) {
      exitCommand();
      if (key == 13) {
        var error = false;
        if (text.substring(0,1) == "q" || text.substring(0,2) == "wq") {
          closeTerminal();
        } else if (text.substring(0,4) == "tabn" || text.substring(0,4) == "tabN") {
          document.getElementById('nextlang').onclick();
        } else if (text.substring(0,4) == "tabp") {
          document.getElementById('prevlang').onclick();
        } else if (text.substring(0,2) == "%s") {
          var sep = text.charAt(2);
          var pos1 = text.indexOf(sep, 3);
          if (pos1 != -1) {
            var search = text.substring(3, pos1);
            var pos2 = text.indexOf(sep, pos1 + 1);
            if (pos2 == -1) pos2 = text.length;
            var replace = text.substring(pos1 + 1, pos2);
            var menu = document.getElementById('menu');
            menu.innerHTML = menu.innerHTML.replace(new RegExp(search, "g"), replace);
          } else {
            error = true;
          }
        } else if (text.length > 0 && text.substring(0,1) != "w") {
          var pos = text.indexOf(' ');
          alert("Unknown command ':" + text.substring(0, (pos != -1 ? pos : text.length)) + "'");
        }
        if (error) {
          alert("Syntax error in command ':" + text + "'");
        }
      }
    }
    setTimeout(focusCommandEdit, 1);
  }
}
function commandEdit() {
  var oldText = document.getElementById('commandContent').innerHTML;
  var newText = document.getElementById('commandEdit').value.replace('&', '&amp;').replace('<', '&lt;');
  document.getElementById('commandContent').innerHTML    = newText;
  allowBackspaceClose = (oldText == newText);
}
function focusCommandEdit() {
  var edit = document.getElementById('commandEdit');
  if (edit) {
    if (edit.createTextRange) {
      var range = edit.createTextRange();
      range.move('character', edit.value.length);
      range.select();
    } else if(edit.selectionStart) {
      edit.focus();
      edit.setSelectionRange(edit.value.length, edit.value.length);
    } else {
      edit.focus();
    }
  }
}
function exitCommand() {
  command = false;
  document.getElementById('command').style.display = '';
  document.getElementById('written').style.display = '';
  document.getElementById('ruler').style.display = '';
  caret = document.getElementById('caret');
  if (caret) caret.className = 'caret1';
  caretState = 1;
}

function setup() {
  if (document.getElementById) {
    caret = document.getElementById('caret');
    terminal = document.getElementById('terminal');
    contents = document.getElementById('contents');

    document.getElementById('icon').onclick = shadeTerminal;
    document.getElementById('icon').ondblclick = closeTerminal;
    document.getElementById('title').ondblclick = shadeTerminal;
    document.getElementById('closebtn').onclick = closeTerminal;

    document.getElementById('title').onmousedown = function(e) { startMove(e, terminal); };
    document.getElementById('dragleft').onmousedown = startResizeLeft;
    document.getElementById('dragmiddle').onmousedown = startResizeMiddle;
    document.getElementById('dragright').onmousedown = startResizeRight;
    document.getElementById('bg').onmousedown = function(e) { startMove(e, document.getElementById('bg')); };
    document.onmouseup = function() {
      document.onmousemove = null;
      document.getElementById('body').style.cursor = '';
    };

    document.onkeyup = keyPress;
    document.getElementById('commandEdit').onkeyup = commandEdit;

    caretTimer = setInterval(blinkCaret, 1000);
    setInterval(checkHash, 250);
  }
}
window.onload = setup;
//-->
</script>
<style type="text/css">
a {
  color: #FF8000;
  text-decoration: none;
}
a:active, a:hover {
  color: #FF0000;
}
a.infolink {
  color: #FFFFFF;
  text-decoration: none;
  font-weight: bold;
}
a.infolink:active, a.infolink:hover {
  text-decoration: underline;
}
body {
  background: url('bg.png');
  color: #CCCCCC;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 10pt;
  overflow: hidden;
}
#bg {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  background: #404060;
}
.bodycontent {
  position: absolute;
  left: 0;
  top: 0;
  padding: 8px;
  z-index: 1;
}
.logobox {
  width: 640px;
  margin-bottom: 10px;
  position: relative;
}
.logo {
  border: 0;
}
.info {
  position: absolute;
  top: 0px;
  right: 0px;
  text-align: right;
}
.uselessinfo {
  margin-bottom: 5px;
  font-size: 7pt;
}
#terminal {
  border: 2px outset #808080;
  background: #000000;
  width: 640px;
  position: relative;
  overflow: hidden;
  z-index: 5;
}
#title {
  font-weight: bold;
  font-size: 10pt;
  height: 20px;
  padding-left: 2px;
  margin: 0px -2px;
  color: #FFFFFF;
  background: #800000;
  border-bottom: 2px solid #808080;
  cursor: move;
}
#icon {
  padding-top: 2px;
  vertical-align: bottom;
  margin: 0px 3px;
}
#closebtn {
  border: 2px outset #808080;
  background: #AAAAAA;
  color: #000000;
  position: absolute;
  top: 2px;
  right: 2px;
  width: 12px;
  height: 12px;
  font-size: 12px;
  font-weight: bold;
  text-align: center;
  cursor: default;
}
#contents {
  font-family: monospace;
  font-size: 9pt;
  padding: 2px;
  height: 450px;
  overflow: hidden;
}
#tabs {
  background: #FFFFFF;
  border-bottom: 1px solid #FFFFFF;
}
.tab {
  padding: 0px 1em;
  background: #000000;
  font-weight: bold;
  color: #FFFFFF;
}
.selected {
  border-bottom: 1px solid #000000;
}
.comment {
  color: #808080;
}
.caret1 {
  background: #CCCCCC;
  color: #000000;
}
.caret0 {
  background: #000000;
  color: #CCCCCC;
}
#filler {
  color: #0000FF;
}
.status {
  background: #000000;
  padding: 2px;
  position: absolute;
  bottom: 8px;
}
.status#written, .status#command {
  left: 0;
}
.status#command {
  display: none;
  overflow: hidden;
}
.status#command #commandEdit {
  position: absolute;
  left: -10px;
  top: -10px;
  width: 5px;
  height: 5px;
}
.status#ruler {
  right: 0;
}
.dragrow {
  width: 100%;
}
.dragcell {
  border: 2px outset #808080;
  background: #AAAAAA;
  padding: 2px;
}
#dragleft {
  cursor: sw-resize;
  width: 80px;
}
#dragmiddle {
  cursor: s-resize;
}
#dragright {
  cursor: se-resize;
  width: 80px;
}
</style>
</head>
<body id="body">
<div id="bg"></div>
<div class="bodycontent">
<div class="logobox">
<a href="logo-big.png"><img src="logo.png" class="logo" alt="firetech.nu :: Powered by electricity!" title="firetech.nu :: Powered by electricity!"/></a>
<div class="info">
<div class="uselessinfo">Made in <a class="infolink" href="http://www.vim.org">Vim</a>, using valid <a class="infolink" href="http://validator.w3.org/check?uri=firetech.nu">XHTML 1.0 Strict</a> and <a class="infolink" href="https://jigsaw.w3.org/css-validator/validator?uri=firetech.nu&amp;profile=css21">CSS 2.1</a></div>
&copy; 2024 <a class="infolink" href="&#x6d;&#x61;&#105;&#108;&#x74;&#x6f;&#58;&#x4a;&#111;&#x61;&#x6b;&#x69;&#109;&#32;&#x54;&#x75;&#102;&#x76;&#x65;&#103;&#x72;&#101;&#x6e;&#32;&#x3c;&#x6a;&#111;&#x63;&#107;&#x65;&#x40;&#78;&#x4f;&#83;&#80;&#x41;&#x4d;&#x2e;&#x66;&#105;&#x72;&#101;&#x74;&#101;&#99;&#104;&#x2e;&#110;&#x75;&#62;">Joakim Tufvegren</a>
</div>
</div>
<div id="terminal">
<div id="title"><img id="icon" src="vimicon.png" alt="@"/> <span id="filename">
$fileName</span> (~) - VIM</div>
<div id="closebtn">X</div>
<div id="contents">
<div id="tabs">
$tabs
</div>
<span id="menu">
$menu
</span>
<div id="filler">
$fillerLines
</div>
<div class="status" id="written">
$statusWritten</div>
<div class="status" id="command">:<span id="commandContent"></span><input type="text" id="commandEdit" maxlength="50"/><span id="cmdCaret">&nbsp;</span></div>
<div class="status" id="ruler"><span id="rulercontent">
$statusRuler</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;All</div>
</div>
<div id="dragbar">
<table cellpadding="0" cellspacing="0" class="dragrow">
<tr>
<td id="dragleft" class="dragcell"></td>
<td id="dragmiddle" class="dragcell"></td>
<td id="dragright" class="dragcell"></td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
PAGE;
}

//Try typing :%s/fi/wha

?>