<?php
//
// Program:		phpPress
//
// Description:	This is a full flat file
// 				system CMS that mimics the
//				organization of goPress.
//				Since goPress server can not
//				be run on a shared server,
//				phpPress will work there and
//				offer easy migration to
//				goPress if the site is moved
//				to a VPS.
//
require 'vendor/autoload.php';

//
// Load libraries used.
//

//
// HandleBars:   https://github.com/zordius/lightncandy
//
use LightnCandy\LightnCandy;

//
// Jade Library: https://github.com/Talesoft/tale-jade
//
use Tale\Jade;

//
// PHP Mailer:  https://github.com/PHPMailer/PHPMailer
//
require 'vendor/phpmailer/phpmailer/PHPMailerAutoload.php';

//
// Slim Router:  http://www.slimframework.com/
//
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

$app = new \Slim\App;

//
// Set an Error Handler.
//
$c = $app->getContainer();
$c['errorHandler'] = function ($c) {
    return function ($request, $response, $exception) use ($c) {
        return $c['response']->withStatus(400)
                             ->withHeader('Content-Type', 'text/html')
                             ->write(ProcessPage($parts['layout'],"ErrorPage"));
    };
};

//
// This line will cause Slim not to catch errors. Please commit out for
// production server.
//
unset($app->getContainer()['errorHandler']);

//
// Get the server.json information in to global site variables.
//

$site = __DIR__ . '/site';
$style = "Basic";
$layout = "SingleCol";
$styleDir = './themes/styling/' . $style;
$layoutDir = './themes/layouts/' . $layout;
$parts = Array();
$parts["CurrentLayout"] = "SingleCol";
$parts["CurrentStyling"] = "Basic";
$parts["ServerAddress"] = "http://localhost:8080";
$parts["SiteTitle"] = "Test Site";
$parts["Sitebase"] = "./site/";
$parts["TemplatBase"] = "./themes/";
$parts["Cache"] = false;
$parts["MainBase"] = "";

//
// Load relevant items in the layouts directory.
//
$parts["layout"] = file_get_contents($layoutDir . '/template.html');

//
// Load relevant items in the styles directory.
//
$parts["404"] = file_get_contents($styleDir . '/404.html');
$parts["footer"] = file_get_contents($styleDir . '/footer.html');
$parts["header"] = file_get_contents($styleDir . '/header.html');
$parts["sidebar"] = file_get_contents($styleDir . '/sidebar.html');
$parts["ErrorPage"] = "<h1 class='Error'>There was a server error!</h1>";

//
// Load everything in the parts directory.
//
$d = dir($site . '/parts/');
while (false !== ($entry = $d->read())) {
    if((strcmp($entry,"..")!=0)&&(strcmp($entry,".")!=0)) {
        $pathparts = pathinfo($entry);
        $parts[basename($pathparts['filename'])] = figurePage($site . '/parts/' . $pathparts['filename']);
    }
 }
 $d->close();

//
// Function:         SetBasicHeader
//
// Description:    This function will set the basic header
//                 information needed.
//
// Inputs:
//                 $response    The response object to be
//                              sent to the browser.
//
function SetBasicHeader($response) {
   $newResponse = $response->withAddedHeader("Cache-Control", "max-age=2592000, cache");
   $newResponse = $newResponse->withAddedHeader("Server", "phpPress - a CMS written in PHP from Custom Computer Tools: http://customct.com.");
   return($newResponse);
}

//
// Array of shortcodes and their functions.
//
$shcodes = Array(
   'box' => function($args, $inside) {
      return("<div class='box'>" . $inside . "</div>");
   },
   'Column1' => function($args, $inside) {
      return("<div class='col1'>" . $inside . "</div>");
   },
   'Column2' => function($args, $inside) {
      return("<div class='col2'>" . $inside . "</div>");
   },
   'Column1of3' => function($args, $inside) {
      return("<div class='col1of3'>" . $inside . "</div>");
   },
   'Column2of3' => function($args, $inside) {
      return("<div class='col2of3'>" . $inside . "</div>");
   },
   'Column3of3' => function($args, $inside) {
      return("<div class='col3of3'>" . $inside . "</div>");
   },
   'php' => function($args, $inside) {
      return("<div class='showcode'><pre type='syntaxhighlighter' class='brush: php'>" . $inside . "</pre></div>");
   },
   'js' => function($args, $inside) {
      return("<div class='showcode'><pre type='syntaxhighlighter' class='brush: javascript'>" . $inside . "</pre></div>");
   },
   'html' => function($args, $inside) {
      return("<div class='showcode'><pre type='syntaxhighlighter' class='brush: html'>" . $inside . "</pre></div>");
   },
   'css' => function($args, $inside) {
      return("<div class='showcode'><pre type='syntaxhighlighter' class='brush: css'>" . $inside . "</pre></div>");
   }
);

//
// Function:      processShortcodes
//
// Description:   This function will expand all
//				  shortcodes in the page given to
//				  it.
//
function processShortcodes($page) {
	global $shcodes;

	$result = "";
	while(preg_match("/\-\[(\w+)(.*)\]\-/i", $page, $match) == 1) {
		$num = count($match);
		$command = $match[1];
		$cmdarg = "";
		if($num > 2) {
			$cmdarg = $match[2];
		}
		$spos = strpos($page,"-[{$command}");
		$result .= substr($page, 0, $spos);
		$page = substr($page,$spos + 4 + strlen($command) + strlen( $cmdarg));
		$sepos = strpos($page,"-[/{$command}]-");
		$inside = trim(substr($page, 0, $sepos));
		if(strcmp($inside,"") != 0) {
			$inside = processShortcodes($inside);
		}
		$page = substr($page, $sepos + 5 + strlen($command));

		//
		// If the command name exists in the
		// shortcodes hash table, then run the
		// funtion.
		//
		if( array_key_exists($command, $shcodes) ) {
			$result .= call_user_func($shcodes[$command], $cmdarg, $inside);
		}
	}
	$result .= $page;
	return($result);
}

//
// Create the HandleBar helpers array.
//
$helpers = Array(
      'flags' => LightnCandy::FLAG_HANDLEBARS | LightnCandy::FLAG_ADVARNAME | LightnCandy::FLAG_EXTHELPER,
      'helpers' => Array(
            'save' => 'save_helper',
            'date' => 'date_helper',
            'cdate' => 'cdate_helper'
         )
   );

//
// Function:         save_helper
//
// Description:      This helper will save the given text to
//                   the given name. That name can be use
//                   latter in the document.
//
// Inputs:
//                   $args    The arguments sent to the
//                            helper function.
//
function save_helper($args) {
   global $parts;

   $arg = implode(" ", $args);
   $hparts = explode("|", $arg);
   if(count($hparts) == 2) {
      $parts[$hparts[0]] = $hparts[1];

      return $hparts[1];
   } else {
      return $parts[$hparts[0]];
   }
}

//
// Function:     date_helper
//
// Description:  This function formats the current date
//               according to the formating string given.
//
// Inputs:
//               $args      The arguments sent to the helper
//
function date_helper($args) {
   $dateFormat = implode(" ", $args);
   return date($dateFormat);
}

//
// Function:     cdate_helper
//
// Description:  This function formats the date given
//               according to the formating string given.
//
// Inputs:
//               $args      The arguments sent to the helper
//
function cdate_helper($args) {
	return date($args[0], $args[1]);
}

//
// Function:        ProcessPage
//
// Description:     This function will process a page into
//                  the template, process all Mustache
//                  macros, and process all shortcodes.
//
// Inputs:
//                  $layout     The layout for the page
//                  $page       The pages main contents
//
function ProcessPage( $layout, $page ) {
   global $site, $parts, $helpers;

   //
   // Get the page contents.
   //
   $parts['content'] = figurePage($page);

   //
   // First pass on Handlebars.
   //
   $phpStr = LightnCandy::compile($layout, $helpers);
   $renderer = LightnCandy::prepare($phpStr);
   $page = $renderer($parts);

   //
   // Process the shortcodes.
   //
   $pageShort = processShortcodes($page);

   //
   // Second pass Handlebars.
   //
   $phpStr = LightnCandy::compile($pageShort, $helpers);
   $renderer = LightnCandy::prepare($phpStr);
   $page = $renderer($parts);

   //
   // Return the results.
   //
   return($page);
}

//
// Setup the routes routines.
//

function page( $pageAddress ) {
   global $site,  $parts;

   $page = ProcessPage( $parts['layout'], "{$site}/pages/{$pageAddress}");
   return($page);
}

function posts($postType, $blog, $pageAddress ) {
   global $site,  $parts;

   $page = ProcessPage( $parts['layout'],"{$site}/posts/{$postType}/{$blog}/{$pageAddress}");
   return($page);
}

function figurePage( $page ) {
   global $site, $parts;

   $result = "";
   if(isset($parts[$page])) {
      //
      // A site partial was specified. Use it.
      //
      $result = $parts[$page];
   }else if(file_exists("{$page}.html")) {
      //
      // It is a html piece. Just get it and pass it on.
      //
      $result = file_get_contents("{$page}.html");
   } else if(file_exists("{$page}.md")) {
      //
      // It is a markdown piece. Process into HTML and pass
      // it on.
      //
      $Parsedown = new Parsedown();
      $result = file_get_contents("{$page}.md");
      $result = $Parsedown->text($result);
      $result = str_replace("&quot;","\"",$result);
   } else if(file_exists("{$page}.amber")) {
      //
      // It is a Jade (using the golang name for the
      // extension) page.
      //
      $jade = new Jade\Renderer();
      $jade->addPath(dirname($page));
      $result = $jade->render(basename($page));
   } else {

      $result = $parts["404"] ;
   }
   //
   // give the resulting page content.
   //
   return($result);
}

//
// This route handles the main or home page.
//
$app->get('/', function(Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse = $newResponse->getBody()->write(page('main'));
   return($newResponse);
});


//
// This route handles the favicon loading.
//
$app->get('/favicon.ico', function(Request $request, Response $response){
   global $site;

   $newResponse = SetBasicHeader($response);
   $newResponse = $newResponse->withAddedHeader("Content-type", "image/ico");
   $newResponse->getBody()->write(file_get_contents("{$site}/images/favicon.ico"));
   return($newResponse);
});


//
// This route handles all the stylesheets loading as one
// sheet.
//
$app->get('/stylesheets', function(Request $request, Response $response) {
   global $site;

   $newResponse = $response->withHeader("Content-type", "text/css");
   $newResponse = SetBasicHeader($newResponse);
   $newResponse->getBody()->write(file_get_contents("{$site}/css/final/final.css"));
   return($newResponse);
});


//
// This route handles the loading of the scripts.
//
$app->get('/scripts', function(Request $request, Response $response) {
   global $site;

   $newResponse = $response->withAddedHeader("Content-type", "text/javascript");
   $newResponse = SetBasicHeader($newResponse);
   $newResponse->getBody()->write(file_get_contents("{$site}/js/final/final.js"));
   return($newResponse);
});


//
// This route handles all the image routes.
//
$app->get('/images/{image}', function(Request $request, Response $response) {
   global $site;

   $ext = pathinfo($request->getAttribute('image'), PATHINFO_EXTENSION);
   $newResponse = SetBasicHeader($response);
   $newResponse = $newResponse->withAddedHeader("Content-type", "image/$ext");
   $newResponse->getBody()->write(file_get_contents("{$site}/images/" . $request->getAttribute('image')));
   return($newResponse);
});

//
// This route handles all the video items.
//
$app->get('/videos/{video}', function(Request $request, Response $response) {
   global $site;

   $newResponse = SetBasicHeader($response);
   $newResponse = $response->withAddedHeader("Content-type", "video/mp4");
   $newResponse->getBody()->write(file_get_contents("{$site}/video/" . $request->getAttribute('video')));
   return($newResponse);
});


//
// This route handles all the blog posts pages.
//
$app->get('/posts/blogs/{blog}', function( Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse->getBody()->write(posts("blogs",$request->getAttribute('blog'), "index"));
   return($newResponse);
});


$app->get('/posts/blogs/{blog}/{post}', function( Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse->getBody()->write(posts("blogs",$request->getAttribute('blog'), $request->getAttribute('post')));
   return($newResponse);
});


//
// This route handles all the news posts pages.
//
$app->get('/posts/news/{news}', function( Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse->getBody()->write(posts("news",$request->getAttribute('news'), "index"));
   return($newResponse);
});

$app->get('/posts/news/{news}/{post}', function( Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse->getBody()->write(posts("news",$request->getAttribute('news'), $request->getAttribute('post')));
   return($newResponse);
});

//
// This route will process all the pages. Since this should
// catch all types of routes other than the home page, this
// route should handle the unknown pages as well.
//
$app->get('/{page}', function( Request $request, Response $response) {
   $newResponse = SetBasicHeader($response);
   $newResponse->getBody()->write(page($request->getAttribute('page')));
   return($newResponse);
});

//
// This route is for processing the post request from the
// email form on the website.
//
$app->post('/api/message', function(Request $request, Response $response) {
    global $_POST;

    //
    // Get the post variables.
    //
    $Name = $_POST['Name'];
    $Email = $_POST['Email'];
    $Message = $_POST['Message'];

    //
    // Create the email message and send it.
    //
    $mail = new PHPMailer;

    $mail->isSMTP();                           // Set mailer to use SMTP
    $mail->Host = 'smtp.gmail.com';            // Specify main and backup SMTP servers
    $mail->SMTPAuth = true;                    // Enable SMTP authentication
    $mail->Username = '<your email address>';   // SMTP username
    $mail->Password = '<your password>';          // SMTP password
    $mail->SMTPSecure = 'tls';                 // Enable TLS encryption, `ssl` also accepted
    $mail->Port = 587;                         // TCP port to connect to

    $mail->setFrom($Email, $Name);
    $mail->addAddress('<your email>', '<your name>');     // Add a recipient

    $mail->Subject = "Message from $Name";
    $mail->Body    = $Message;

    if(!$mail->send()) {
        echo 'Message could not be sent.';
        echo 'Mailer Error: ' . $mail->ErrorInfo;
    } else {
        $newResponse = SetBasicHeader($response);
        $newResponse->getBody()->write(page('messagesent'));
        return($newResponse);
    }
});

//
// Respond to requests.
//
$app->run();

?>
