<?php

/*************************************************************************
 * My Hours Timer                                                        *
 * Copyright (c) 2007, Peter Goodman                                     *
 *                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining *
 * a copy of this software and associated documentation files (the       *
 * "Software"), to deal in the Software without restriction, including   *
 * without limitation the rights to use, copy, modify, merge, publish,   *
 * distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to *
 * the following conditions:                                             *
 *                                                                       *
 * The above copyright notice and this permission notice shall be        *
 * included in all copies or substantial portions of the Software.       *
 *                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                 *
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS   *
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN    *
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN     *
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE      *
 * SOFTWARE.                                                             *
 *************************************************************************/
                                                                          
error_reporting(E_ALL);

// the app name
define ('APP_NAME''My Hours Timer');

// sqlite
define ('SQLITE_FILE'dirname(__FILE__) .'/db.sqlite');

// start a session
session_start();



function 
html_header()
{
    echo 
'
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>'
APP_NAME .'</title>
    '
;
    
header_javascript();
    
header_css();
    echo 
'
</head>
<body>
<div align="center">
<div id="wrap">
    '
;
}

function 
html_footer()
{
    echo 
'
</div>
</div>
</body>
</html>
    '
;
}

function 
header_javascript()
{
    echo 
'
    <script type="text/javascript">
    var running = [];
    
    var L = {
        DEL_TIMER: \'Are you sure that you want to delete this row?\',
        RESTART_TIMER: \'You need to stop all other timers before restarting this one.\',
        CONFIRM_LOGOUT: \'Are you sure that you want to logout?\',
        ADD_TIMER: \'Whoops! There is already a timer active. You will need to stop it to start a new one.\'
    };
    
    function currentlyRunning(id) {
        running.push(id);
    }
    function add() {
        if(running.length > 0) {
            alert(L.ADD_TIMER);
            return;
        }
        var add_form = document.getElementById(\'add_timer_form\');
        add_form.style.display = (add_form.style.display == \'block\' ? \'none\' : \'block\');
    }
    </script>
    '
;
}

function 
header_css()
{
    echo 
'
    <style type="text/css">
    body {
        padding: 0;
        margin: 0;
        background: #fff;
        font: 0.8em arial, helvetica, sans-serif;
    }
    form {
        padding: 0;
        margin: 0;
    }
    h3 {
        margin: 1em 0 0 0;
        text-align: left;
    }
    #wrap {
        width: 600px;
    }
    .rounded {
        -moz-border-radius: 5px;
        -webkit-border-radius: 5px;
    }
    table {
        border: 0;
        background: #C3D9FF;
        padding: 10px;
    }
    th {
        background: #E0ECFF;
        color: #999;
        text-align: left;
    }
    td, th {
        padding: 5px;
        border-bottom: 1px solid #ccc;
    }
        td.started {
            color: #006633;
            font-size: 0.8em;
        }
        td.running_time {
            color: #000;
        }
        td.description {
            color: #817777;
            font-size: 0.8em;
        }
            td.description em {
                color: #999;
            }
    tr.done td {
        background: #E8EEF7;
    }
    tr.not_done td {
        background: #fff;
    }
    tr.total {
        background: #FFF7D7;
        text-align: right;
    }
    a {
        text-decoration: none;
        color: #000;
    }
    .menu, .login {
        margin-top: 1em;
        color: #728388;
    }
        .menu a {
            color: #000;
        }
    .timer_form {
        display:none;        
        
    }
    .login_form, .timer_form {
        background: #74DD82;
        padding: 10px;
        margin-top: 1em;
        text-align: left;
    }
    input[type=submit] {
        border: 2px outset;
        background-color: #fff;
    }
    input[type=text], input[type=password], textarea {
        border: 2px solid #ccc;
        padding: 5px;
        font: 1em arial, helvetica, sans-serif;
    }
    </style>
    '
;
}

function 
timer_table()
{
    
$header '';
    
    if(
is_logged())
        
$header ' &bull; '$_SESSION['user']['name'];
    
    echo 
'
    <h3>'
APP_NAME $header .'</h3>
    <table width="100%" cellpadding="0" cellspacing="0" class="rounded">
        <tr>
            <th width="10%">Started</th>
            <th width="10%" nowrap="nowrap">Running Time</th>
            <th width="70%">Description</th>
            <th width="10%"> </th>
        </tr>
        <tbody>
    '
;
    
    
$time 0;
    
    if(
is_logged())
    {
        
$res query("SELECT * FROM timers WHERE user_id=? ORDER BY id DESC", array($_SESSION['user']['id']));
    
        while(
nextResult($res))
        {
            
$row currentResult($res);
        
            
$time += timer_row($row['id'], $row['start_time'], $row['end_time'], $row['desc'], $row['duplicate_id']);
        }
    }
    else
    {
        echo 
'
        <tr class="not_done">
            <td colspan="4" style="text-align:center;padding:2em;">
                Register or log in to keep track of your hours!
            </td>
        </tr>
        '
;
    }
    
    echo 
'
        </tbody>
    '
;
    
    
timer_total($time);
    
    echo 
'
    </table>
    '
;
}

function 
timer_row($id 0$start_time 0$end_time 0$desc ''$duplicate_id 0)
{
    
$done = ($end_time != 0);
    
$end = ($done $end_time time());
    
    
$running_time $end $start_time;
    
    
// controls
    
$stop '<a href="index.php?stop='$id .'">stop</a><script type="text/javascript">currentlyRunning('$id .');</script>';
    
$restart $duplicate_id == '<a href="index.php?restart='$id .'" onclick="if(running.length>0){alert(L.RESTART_TIMER);return false;}">restart</a> &bull; ' '';
    
$delete '<a href="index.php?delete='$id .'" onclick="if(!confirm(L.DEL_TIMER))return false;">delete</a>';
    
    
// output the row
    
echo '
            <tr class="'
. ($done 'done' 'not_done') .'">
                <td class="started" nowrap="nowrap">'
date("F j, Y, g:i a"$start_time) .'</td>
                <td class="running_time" nowrap="nowrap">'
round(($end $start_time) / 36002) .' hours</td>
                <td class="description">'
parse_repeat_description($desc) .'</td>
                <td nowrap="nowrap">
                '
. (is_logged() ? (!$done $stop $restart $delete) : '') .'
                </td>
            </tr>
    '
;
    
    return 
$running_time;
}

function 
timer_total($total_time 0)
{
    
    
$hours floor($total_time 3600);
    
$hours $hours $hours;
    
    
$minutes floor(($total_time - ($hours 3600)) / 60);
    
$minutes $minutes $minutes;
    
    
$seconds $total_time - ($hours 3600) - ($minutes 60);
    
    echo 
'
        <tr class="total">
            <td colspan="4">
                <b>Total:</b> <em>'
$hours .' hours, '$minutes .' minutes, and '$seconds .' seconds.</em>
            </td>
        </tr>
    '
;
    
}

function 
menu()
{
    if(
is_logged())
    {
        echo 
'
        <div class="menu">
            <a href="javascript:;" onclick="add()">add new</a>
            &bull; <a href="index.php?logout" onclick="if(!confirm(L.CONFIRM_LOGOUT))return false;">logout</a>
        </div>
        '
;
    }
    else
    {
        echo 
'
        <div class="login_form rounded">
            <form method="post" id="login_form" action="index.php?login" enctype="multipart/form-data"> 
            <label for="user_name">name:</label> <input type="text" name="user_name" id="user_name" value="" size="10" tabindex="1" />
            <label for="password">pass:</label> <input type="password" name="password" id="password" value="" size="10" tabindex="2" />
            <input type="button" value="login" onclick="f=document.getElementById(\'login_form\');f.action=\'index.php?login\';f.submit();" />
            <input type="button" value="register" onclick="f=document.getElementById(\'login_form\');f.action=\'index.php?register\';f.submit();" />
            </form>
        </div>
        '
;
    }
}

function 
add_timer_form()
{
    if(
is_logged())
    {
        echo 
'
        <div id="add_timer_form" class="timer_form rounded">
            <form method="post" action="index.php?add" enctype="multipart/form-data">
                <label for="description">description:</label>
                <br />
                <textarea name="description" id="description" rows="3" cols="50" tabindex="1"></textarea>
                <br />
                <input type="submit" value="start timer" />
            </form>
        </div>
        '
;
    }
}

function 
is_logged()
{
    if(isset(
$_SESSION['user']) && $_SESSION['user']['id'] > 0)
        return 
TRUE;
        
    return 
FALSE;
}

function 
login($name$pass)
{
    
$res query("SELECT * FROM users WHERE name=? AND pass=?", array($namehash_pass($pass)));
    
    unset(
$_SESSION['user']);
    
    if(
nextResult($res))
    {
        
$_SESSION['user'] = currentResult($res);
    }
}

function 
stop_timer($id)
{
    if(
is_logged())
    {
        
try {
            
query("UPDATE timers SET end_time=? WHERE id=?", array(time(), $id));
        } 
catch(Exception $e) {
            die(
$e->getMessage());
        }        
    }
}

function 
add_timer($description)
{
    if(
is_logged())
    {
        
try {
            
query("INSERT INTO timers (start_time,end_time,desc,user_id) VALUES (?,?,?,?)", array(time(), 0parse_description($description), $_SESSION['user']['id']));
        } 
catch(Exception $e) {
            die(
$e->getMessage());
        }
    }
}

function 
parse_description($str$undo FALSE)
{
    
$str trim($str);
    
    if(!
$undo)
    {
        
$str htmlentities($strENT_QUOTES'UTF-8');
        
$str preg_replace("~(\r?\n)~""<br />"$str);
    }
    else
    {
        
$str str_replace('<br />'"\n"$str);
        
$str html_entity_decode($strENT_QUOTES'UTF-8');
    }
    return 
$str;
}

function 
parse_repeat_description($str)
{
    
$str preg_replace("~(\[Continued from([^\]]+))\]~""<em>Continued from $2</em>"$str);
    
    return 
$str;
}

function 
delete_timer($id)
{
    if(
is_logged())
    {
        
try {
            
query("DELETE FROM timers WHERE id=?", array($id));
        } 
catch(Exception $e) {
            die(
$e->getMessage());
        }        
    }
}

// this technically makes a new timer ;)
function restart_timer($id 0)
{
    if(
is_logged())
    {
        
$result query("SELECT * FROM timers WHERE end_time=0 AND user_id=?", array($_SESSION['user']['id']));
    
        if(!
nextResult($result))
            
try {
                
//query("UPDATE timers SET end_time=0 WHERE id=?", array($id));
                
                
$res query("SELECT * FROM timers WHERE id=?", array($id));
                
                if(
nextResult($res))
                {
                    
$row currentResult($res);
                    
                    
$description parse_description($row['desc'], TRUE);
                    
                    
add_timer($description "\n" '[Continued from 'date("F j, Y, g:i a"$row['end_time']) .']'$row['id']);
                    
                    
// update the old one so we can't restart it again :P
                    
query("UPDATE timers SET duplicate_id=? WHERE id=?", array(insertId(), $id));
                }
                else
                    die(
"The timer that you are trying to restart doesn't exist");
                
            } 
catch(Exception $e) {
                die(
$e->getMessage());
            }
    }
}

// database functions

function database($val FALSE)
{
    static 
$conn;
    
    if(
$conn === NULL)
    {
        if(!
file_exists(SQLITE_FILE))
        {
            
$fp fopen(SQLITE_FILE"w+");
            
            if(
$fp === FALSE)
                
throw new Exception("Could not create database file.");
            
            if(
$val)
                
fwrite($fp$val);
                
            @
chmod(SQLITE_FILE0777);
        }
        
        if(!
is_readable(SQLITE_FILE) || !is_writable(SQLITE_FILE))
            
throw new Exception("Database file cannot be read.");
        
        
$conn sqlite_open(basename(SQLITE_FILE), 0777$error);
        
        if(
$conn === FALSE || !is_resource($conn))
            
throw new Exception("Could not connect to the database [{$error}]");    
    }
    
    return 
$conn;
}

function 
add_values_to_sql($sql$args)
{
    
// there's prolly a better way of doing this but
    // I'm being lazy and just doing it this way.
    
foreach($args as $key => $val)
    
        
// if this is not an integer value, put quotes
        // around it
        
if(!ctype_digit($val))
            
$args[$key] = "'"sqlite_escape_string($val) ."'";
    
    
$sql str_replace(array('%''?'), array('%%''%s'), $sql);
    
    
$sql vsprintf($sql$args);
    
    return 
str_replace('%%''%'$sql);
}


function 
query($stmt ''$args = array())
{
    
$stmt add_values_to_sql($stmt$args);
    
    
try {
        
$result sqlite_query(database(), $stmt);
    } 
catch(Exception $e) {
        die(
$e->getMessage());
    }
    
    if(
$result === FALSE || !is_resource($result))
        
throw new Exception("An error occured while querying the database ["sqlite_error_string(sqlite_last_error(database())) ."]");
        
    return 
$result;
}

function 
nextResult(&$result)
{
    return 
sqlite_has_more($result);
}
function 
currentResult(&$result)
{
    return 
sqlite_fetch_array($resultSQLITE_ASSOC);
}
function 
insertId()
{
    return 
sqlite_last_insert_rowid(database());
}

function 
hash_pass($str)
{
    return 
md5($str md5('abcdefghijklmnopqrstuvwxyz'));
}
    
$action array_keys($_GET);

if(isset(
$action[0]))
{
    switch(
$action[0])
    {
        case 
'login':
            
login($_POST['user_name'], $_POST['password']);
            break;
        case 
'logout':
            if(isset(
$_SESSION['user']))
                unset(
$_SESSION['user']);
            break;
        case 
'register':
            
$res query("SELECT * FROM users WHERE name=?", array($_POST['user_name']));
            
            if(
nextResult($res))
                die(
"A user with that name already exists. Please try another.");
            
            
query("INSERT INTO users (name,pass) VALUES (?,?)", array($_POST['user_name'], hash_pass($_POST['password'])));
            
login($_POST['user_name'], $_POST['password']);
            
            break;
        case 
'add':
            
add_timer($_POST['description']);
            break;
        case 
'stop':
            
stop_timer($_GET['stop']);
            break;
        case 
'delete':
            
delete_timer($_GET['delete']);
            break;
        case 
'restart':
            
restart_timer($_GET['restart']);
            break;
        case 
'install':
            
            
// don't want to allow website people to
            // drop the database.
            
if(file_exists(SQLITE_FILE))
                die(
"The database already exists. Please remove it manually with FTP or SSL.");
        
            
try 
            
{
                
query("CREATE TABLE timers (
                    id INTEGER UNSIGNED,
                    start_time INTEGER UNSIGNED NOT NULL DEFAULT 0,
                    end_time INTEGER UNSIGNED NOT NULL DEFAULT 0,
                    desc TEXT,
                    duplicate_id INTEGER UNSIGNED NOT NULL DEFAULT 0,
                    user_id INTEGER UNSIGNED NOT NULL DEFAULT 0,
                    PRIMARY KEY (id)
                )"
, array());
                
                
query("CREATE TABLE users (
                    id INTEGER UNSIGNED,
                    name VARCHAR(30) NOT NULL,
                    pass VARCHAR(32) NOT NULL,
                    PRIMARY KEY (id)
                )"
, array());
            }
            
catch(Exception $e) {
                die(
$e->getMessage());
            }
            break;
    }
    
    
header("Location: index.php");
    exit;
}
// do the normal stuff anyway

html_header();

menu();

add_timer_form();

timer_table();

html_footer();

?>