<?php

    
// VERSION = 1.0

    /***************************************************
     * FUNCTIONS:
     *
     * draw_%    - Draws a form widget of type "%".
     *          If any problems, will list them
     *          in $errors. End users should never
     *          see such errors!
     *
     * rpt_%    - Reports on a form widget of type "%".
     *          A "read only" version of "Draw" basically.
     *
     * chk_%    - Checks that form widget of type "%"
     *          has been correctly filled out, and
     *          returns the data supplied by the
     *          user. 
     *          If not filled out correctly, will
     *          place an error message in $errors
     *          and list it as a field that requires
     *          highlighting in $highlight.
     *
     * chk_Form    - Special case of chk_%. Reads the
     *          initial form widget to discover 
     *          options.
     *
     * data_CreateDatabase - handy function that tells
     *          you what database structure is
     *          needed.
     *
     * data_StoreSubmission - given a surveyid and username,
     *          creates a submission, returning the
     *          submissionid.
     *
     * data_StoreAnswer - given a submissionid, question code
     *          and answer, stores the answer.
     *
     * data_FindSubmissions - given a surveyid and username,
     *          finds any previous submissions and
     *          returns those submissionids as an
     *          array.
     *
     * data_DestroySubmission - destroys a submission.
     *
     * data_RetriveAnswers - given a submission ID,
     *          retrieves associated answers.
     *          If optional second attribute is
     *          set to 1, will over-ride username
     *          check.
     *
     * form_Whois    - Gets user name from somewhere.
     *
     * form_Prefill    - This is called by form_Draw to
     *          set default answers.  
     *
     * form_Draw    - Draws the initial form. Is passed
     *          a list of default answers.
     *
     * form_Report    - Draws the report, given a list
     *          of answers.
     *
     * form_Chk    - Checks the form. Redisplays form
     *          and returns FALSE if not filled out
     *          correctly; and returns $answers if
     *          correct.
     *
     * form_Email    - Sends off the form results by
     *          e-mail if that's required.
     *
     * form_Save    - Saves the answers to a database.
     *          Returns 0 if could not save; returns
     *          a positive integer (submission ref)
     *          if all is OK.
     *
     * form_Main    - Does everything!
     *
     ***************************************************/


    // GLOBALS
    
$prefixStyle    'frm_';
    
$prefixIdent    'frm_ident_';
    
$prefixRequest    'frm_req_';
    
$errors     = array();
    
$highlight     = array();
    
$options    = array();
    
$prefixSubj    'Form submission: ';
    
$mailtoHeaders    "From: You <you@example.com>\r\n\r\n";
    
    
// DATABASE
    
$prefixData    'survey_';
    
$database    pg_connect('dbname=web');
    
$databasetype    1;     // 1 = PostgreSQL, 
                // 2 = MySQL (untested).

    // UNITS
    
$units['Currency']     = array('GBP''EUR''US$');
    
$units['Length']     = array('kilometre''metre''centimetre''millimetre''mile''yard''foot''inch');
    
$units['Area']        = array('km^2''hectare''m^2''cm^2''mm^2''mile^2''acre''foot^2''inch^2');
    
$units['Volume']    = array('kilolitre''litre''millilitre''brpint''fluidounce''m^2''cm^2''mm^2');
    
$units['Weight']    = array('kilogram''gram''pound''ounce');
    
$units['Time']        = array('year''month''week''day''hour''minute''second');
    
$units['Speed']     = array('km/hour''miles/hour''m/s');
    
$prefunit['Currency']    = 'GBP';
    
$prefunit['Length']    = 'metre';
    
$prefunit['Area']    = 'm^2';
    
$prefunit['Volume']    = 'litre';
    
$prefunit['Weight']    = 'kilogram';
    
$prefunit['Time']    = 'second';
    
$prefunit['Speed']    = 'm/s';
    
$unitspath         '/usr/bin/units';
    
    
/***************************************************
     * draw_% functions
     ***************************************************/

    
function draw_Widget ($params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$errors;
        
        
$w $params[0];
        
        if (
$w=='')
            return 
NULL;
        
        if (
function_exists("draw_{$w}"))
        {
            
$retval call_user_func("draw_{$w}"$params$data$answers$ret);
            if (
$ret)
                return 
$retval;
            print 
$retval;
        }
        else
        {
            
$errors[] = "Did not understand widget {$w}";
            if (
$ret)
                return 
NULL;
        }
        
            
    }

    function 
draw_Heading $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        list(
$id$txt) = explode('='$data);
        
        
$idstr '';
        if (
$id)
            
$idstr ' id="' $prefixIdent $id '"';
        
        if (
$params[0]=='Heading')
            
$tag 'h2';
        else
            
$tag 'h3';
        
        
$retval "<{$tag}{$idstr} class=\"{$prefixStyle}{$params[0]}\">"
                
htmlspecialchars($txt)
                . 
"</{$tag}>\n";
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }


    function 
draw_Subheading $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Heading ($params$data$answers$ret);
    }


    function 
draw_Note $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$retval "<div class=\"{$prefixStyle}{$params[0]}\">$data</div>\n";
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }

    function 
draw_BigNote $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Note ($params$data$answers$ret);
    }
    
    function 
draw_Rule $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$retval "<hr class=\"{$prefixStyle}Rule\">\n";
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }
    
    function 
draw_Text $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
            
        list(
$code$label) = explode('='$data);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
                
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
        
        if (
$params[0]=='Text' || $params[0]=='SmallText')
            if (
$params[2]>0)
                
$mlstr ' maxlength="' $params[2] . '"';
        
        
$brstr '<br>';
        if (
$params[0]=='SmallText' || $params[0]=='Integer'
                        
|| $params[0]=='Date' )
            
$brstr '';
        
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <label class=\"majorlabel\" for=\"{$prefixIdent}{$code}\">"
                
htmlspecialchars($label)
                . 
"</label>{$brstr}\n";
        
$retval .= "  <input{$mlstr} id=\"{$prefixIdent}{$code}\""
                
" name=\"{$prefixRequest}{$code}\""
                
" value=\"".htmlspecialchars($answers[$code])."\""
                
">{$brstr}\n";
        if (
$params[0]=='Date')
            
$retval .= "  <small>(Enter a date in an unambiguous format.)</small>\n";
        if (
$params[0]=='Integer' && $params[1]>&& $params[2]>0)
            
$retval .= "  <small>(Enter a number between {$params[1]} and {$params[2]}.)</small>\n";
        elseif (
$params[0]=='Integer')
            
$retval .= "  <small>(Enter a number.)</small>\n";
        if (
$params[0]=='Email')
            
$retval .= "  <small>(Enter an e-mail address, including the @-sign.)</small>\n";
        if (
$params[0]=='WWW')
            
$retval .= "  <small>(Enter a website address, including the \"http://\".)</small>\n";
        
$retval .= "</div>\n";        
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }    
    
    function 
draw_SmallText $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Text ($params$data$answers$ret);
    }

    function 
draw_Integer $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Text ($params$data$answers$ret);
    }

    function 
draw_Date $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Text ($params$data$answers$ret);
    }

    function 
draw_Email $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Text ($params$data$answers$ret);
    }


    function 
draw_WWW $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_Text ($params$data$answers$ret);
    }


    function 
draw_Units $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight$units;
            
        list(
$code$label) = explode('='$data);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
                
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
                        
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <label class=\"majorlabel\" for=\"{$prefixIdent}{$code}_origval\">"
                
htmlspecialchars($label)
                . 
"</label>{$brstr}\n";
        
$retval .= "  <input{$mlstr} size=\"6\" id=\"{$prefixIdent}{$code}_origval\""
                
" name=\"{$prefixRequest}{$code}_origval\""
                
" value=\"".htmlspecialchars($answers["{$code}_origval"])."\""
                
"> \n";
        
        
$retval .= "  <select{$liststr} id=\"{$prefixIdent}{$code}_origunit\" "
                
"name=\"{$prefixRequest}{$code}_origunit\">\n";
        
        
$dimension $params[1];
        
$n 0;
        
        while (
$u array_shift($units[$dimension]))
        {
            
$selstr '';
            if (
$answers["{$code}_origunit"]==$u)
                
$selstr ' selected';
            elseif (!isset(
$answers["{$code}_origunit"]) && $params[2]==$n)
                
$selstr ' selected';

            
$retval .= "    <option{$selstr}>" htmlspecialchars($u) . "</option>\n";
            
            
$n++;
        }
        
$retval .= "  </select>\n";


        
$retval .= "</div>\n";        
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }

    function 
draw_BigText $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        list(
$code$label) = explode('='$data);        
        if (
$highlight[$code]) $highlightStr 'highlightfield ';

        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
        
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <label class=\"majorlabel\" for=\"{$prefixIdent}{$code}\">"
                
htmlspecialchars($label)
                . 
"</label><br>\n";
        
$retval .= "  <textarea rows=\"6\" cols=\"60\" id=\"{$prefixIdent}{$code}\""
                
" name=\"{$prefixRequest}{$code}\">"
                
htmlspecialchars($answers[$code])
                . 
"</textarea>\n";
        if (
$params[0]=='RichText')
            
$retval .= "  <br><small>(Accepts HTML input.)</small>\n";
        
$retval .= "</div>\n";        
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }    


    function 
draw_RichText $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_BigText ($params$data$answers$ret);
    }


    function 
draw_SingleRadio $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$D explode("\n"$data);
        
        
$d array_shift($D);
        list(
$code$label) = explode('='$d);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
        
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
        
        if (
$params[1] == 'Compact')
            
$brstr ' &nbsp; &nbsp; ';
        else
            
$brstr '<br>';
        
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <span class=\"majorlabel\">" htmlspecialchars($label) . "</span>{$brstr}\n";

        while (
$d array_shift($D))
        {
            list(
$c$l) = explode('='$d);
            if (
$c=='')
                
$errors[] = "draw: option must have a code.";
            if (
$l=='')
                
$errors[] = "draw: option have a label.";
            
            
$selstr '';
            if (
$answers[$code]==$c)
                
$selstr ' checked';

            
$retval .= "  <input{$selstr} type=\"radio\" id=\"{$prefixIdent}{$code}_{$c}\" "
                    
"name=\"{$prefixRequest}{$code}\" value=\"{$c}\">\n"
                    
"  <label for=\"{$prefixIdent}{$code}_{$c}\">"
                    
htmlspecialchars($l) . "</label>{$brstr}\n";
        }
        
$retval .= "</div>\n";        
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }

    function 
draw_Single $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_SingleRadio ($params$data$answers$ret);
    }


    function 
draw_SingleDropdown $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$D explode("\n"$data);
        
        
$d array_shift($D);
        list(
$code$label) = explode('='$d);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
        
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
        
        
$brstr '<br>';
        if (
$params[1]=='Compact' && $params[0]!='SingleList')
            
$brstr '';
            
        if (
$params[0]=='SingleList')
            
$liststr ' size="6"';
        
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" "
                
"id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <label class=\"majorlabel\" for=\"{$prefixIdent}{$code}\">" 
                
htmlspecialchars($label) . "</label>{$brstr}\n";
        
$retval .= "  <select{$liststr} id=\"{$prefixIdent}{$code}\" "
                
"name=\"{$prefixRequest}{$code}\">\n";
        
        while (
$d array_shift($D))
        {
            list(
$c$l) = explode('='$d);
            if (
$c=='')
                
$errors[] = "draw: option must have a code.";
            if (
$l=='')
                
$errors[] = "draw: option have a label.";
            
            
$selstr '';
            if (
$answers[$code]==$c)
                
$selstr ' selected';

            
$retval .= "    <option{$selstr} value=\"{$c}\">"
                    
htmlspecialchars($l) . "</option>\n";
        }
        
$retval .= "  </select>\n";
        
$retval .= "</div>\n";
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }

    function 
draw_SingleList $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_SingleDropdown ($params$data$answers$ret);
    }


    function 
draw_YesNo $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        
$P = array('Single''Compact');
        
$D $data "\nyes=Yes\nno=No";
        return 
draw_Single ($P$D$answers$ret);
    }


    function 
draw_MultiCheckbox ($params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$D explode("\n"$data);
        
        
$d array_shift($D);
        list(
$code$label) = explode('='$d);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
        
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
                
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <span class=\"majorlabel\">" htmlspecialchars($label) . "</span><br>\n";

        while (
$d array_shift($D))
        {
            list(
$c$l) = explode('='$d);
            if (
$c=='')
                
$errors[] = "draw: option must have a code.";
            if (
$l=='')
                
$errors[] = "draw: option have a label.";
            
            
$selstr '';
            if (
$answers["{$code}_{$c}"]=='on')
                
$selstr ' checked';

            
$retval .= "  <input{$selstr} type=\"checkbox\" id=\"{$prefixIdent}{$code}_{$c}\" "
                    
"name=\"{$prefixRequest}{$code}_{$c}\" value=\"on\">\n"
                    
"  <label for=\"{$prefixIdent}{$code}_{$c}\">"
                    
htmlspecialchars($l) . "</label><br>\n";
        }
        if (
$params[1]>|| $params[2]>0)
            
$retval .= "  <small>(Minimum $params[1], maximum $params[2] choices.)</small>\n";
        
$retval .= "</div>\n";        
        
        if (
$ret)
            return 
$retval;
        else
            echo 
$retval;
    }

    function 
draw_Multi $params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        return 
draw_MultiCheckbox ($params$data$answers$ret);
    }
    
    function 
draw_GridMulti ($params=array(), 
                
$data='',
                
$answers=array(),
                
$ret=0)
    {
        global 
$prefixStyle$prefixIdent$prefixRequest,
            
$errors$highlight;
        
        
$D explode("\n"$data);
        
        
$d array_shift($D);
        list(
$code$label) = explode('='$d);
        if (
$highlight[$code]) $highlightStr 'highlightfield ';
        
        if (
$code=='')
            
$errors[] = "draw: {$params[0]} widgets must have a code.";

        if (
$label=='')
            
$errors[] = "draw: {$params[0]} widgets must have a label.";
            
        
$textboxes explode(','$params[3]);
        foreach (
$textboxes as $t)
            
$txt[$t] = 1;
                
        
$retval '';
        
$retval .= "<div class=\"{$highlightStr}{$prefixStyle}{$params[0]}\" id=\"{$prefixIdent}wrap_{$code}\">\n";
        
$retval .= "  <span class=\"majorlabel\">" htmlspecialchars($label) . "</span><br>\n";

        while (
$d array_shift($D))
        {
            if (
strtoupper($d)=='COLS')
                
$axis 'x';
            elseif (
strtoupper($d)=='ROWS')