<?php

if (!defined('DOKU_INC')) die();

class helper_plugin_conform extends DokuWiki_Plugin 
{
    function getInfo()
    {
        return array(
            'author' => 'William Fletcher',
            'email'  => 'uiriamu.furecchaa@gmail.com',
            'date'   => '2008-09-08',
            'name'   => 'conform',
            'desc'   => 'Creates HTML forms properly',
            'url'    => 'http://http://thirdforces.internationalconspiracy.org/~ultraviolet/software/conform/',
        );
    }

    function getMethods() 
    {
        $result = array();
        $result[] = array(
                'name'   => 'conformExtract',
                'desc'   => 'Absorbs the raw form information, syntax checks it and places it in a neat array for further processing',
                );
        return $result;
    }

    function conformExtract ( $data )
    {
        $lines = explode(';', $data);
        $errors = array();
        $argcheck = array(
                            'MailTo'      => 2,
			    'MailSubject' => 2, 
                            'Textbox'     => 4,
                            'Constraint'  => 4,
                            'Select'      => 5,
                            'Textarea'    => 5,
                            'Radio'       => 4,
                            'Checkbox'    => 4,
                            'Line'        => 1,
                            'Static'      => 2,
                            'Submit'      => 3,
                            'RowsStart'   => 2,
                            'RowsEnd'     => 1
                         );
        $linecount               = 0;
        $tablemode               = 0;
        $tables                  = array();
        $tablecount              = 0;
        $attrs                   = array();
        $required                = array();
        $attributes              = array();
        $constraints             = array();
	$constraintargs          = array();
        $maxcolumns              = 0;
        $required['MailTo']      = 0;
        $required['Submit']      = 0;
	$required['MailSubject'] = 0;
        foreach ($lines as $line)
        {
            $linecount++;
            if (empty($line) || preg_match("/^\s*$/", $line)) continue;
            $args = $this->conformTemplateLineParse($line);
            if ( ! array_key_exists($args[0], $argcheck) )
            {
                array_push($errors, "Line: $linecount --> Keyword '$args[0]' doesn't exist!");
                continue;
            }
            else
            {
                if ( count($args) != $argcheck[$args[0]] )
                {
                    array_push($errors, "Line: $linecount --> Keyword '$args[0]' has the wrong number (".count($args).") of arguments!");
                }
                else if ( count($args) > 1 )
                {
                    $lowerattribute = strtolower($args[1]);
                    switch ( $args[0] )
                    {
                        case 'MailTo':
			case 'MailSubject':
			    if ( $required[$args[0]] == 1 )
			    {
				array_push($errors, "Line: $linecount --> Keyword '$args[0]' is repeated!");
			    }
                            break;

			case 'RowsStart':
			case 'Static':
			    break;

                        case 'Constraint':
                            if ( ! is_array($constraints[$lowerattribute]) ) $constraints[$lowerattribute] = array();
                            array_push($constraints[$lowerattribute], $linecount);
                            break;

                        default:
                            if ( preg_match("/_/", $lowerattribute) )
                            {
                                array_push($errors, "Line: $linecount --> Attribute '$args[1]' isn't allowed to contain a _ character!");
                            }
                            if ( in_array($lowerattribute, $attributes) )
                            {
                                array_push($errors, "Line: $linecount --> Attribute '$args[1]' is repeated!");
                            }
                            else
                            {
                                array_push($attributes, $lowerattribute);
                            }
                    }
                }
            }
            switch ( $args[0] )
            {
                case 'MailTo':
		    $emailtoallow       = $this->conformList($this->getConf('conformEmailAllow'));
		    $emailto            = $args[1];
		    $emailtolist        = $this->conformList($args[1]);
		    foreach ( $emailtolist as $mailto )
		    {
			if ( ! in_array($mailto, $emailtoallow) )
			{
			    array_push($errors, "Line: $linecount --> E-mail address $mailto not in allowlist!");
			}
		    }
                    $required[$args[0]] = 1;
                    break;
		case 'MailSubject':
		    $required[$args[0]] = 1;
		    $emailsubject       = $args[1];
		    break;
                case 'RowsStart':
                    if ( count($tables) != 0 ) $tablecount++;
                    $tablemode = 1;
                    $this->conformTablesCreate($tables, $tablecount, $tablemode);
                    if ( ! is_numeric($args[1]) ) $args[1] = 1;
                    $tables[$tablecount]['rows']     = $args[1];
                    $tables[$tablecount]['complete'] = 0;
                    break;
                case 'RowsEnd':
                    $columns = count($tables[$tablecount]['args']);
                    if ( $columns > $maxcolumns ) $maxcolumns = $columns;
                    $tables[$tablecount]['columns'] = ($columns - 1);
                    $tables[$tablecount]['complete'] = 1;
                    $tablemode = 0;
                    $tablecount++;
                    $this->conformTablesCreate($tables, $tablecount, $tablemode);
                    break;
		case 'Constraint':
		    $check = explode("=", $args[3], 2);
		    switch($check[0])
		    {
			case 'maxLength':
			case 'minLength':
			    break;
			default: 
			    array_push($errors, "Constraint '$args[1]' isn't contains incorrect check $check[0]!");
		    }
		    array_push( $constraintargs, $args );
		    break;
                case 'Submit':
                    $required[$args[0]] = 1;
		case 'Radio':
		case 'Select':
		    $args[3] = $this->conformList($args[3]); 
                default:
                    if ( count($tables) == 0 && $tablecount == 0 )
                    {
                        $this->conformTablesCreate($tables, $tablecount, $tablemode);
                    }
                    array_push( $tables[$tablecount]['args'], $args );
                    break;
            }
        }
        foreach ( $required as $requiredcheck => $requiredvalue )
        {
            if ( $requiredvalue != 1 ) array_push($errors, "$requiredcheck keyword is required to exist!");
        }
        foreach ( $constraints as $constraint => $constraintlines )
        {
            if ( ! in_array($constraint, $attributes) )
            {
                foreach ( $constraintlines as $constraintline )
                {
                    array_push($errors, "Line: $constraintline --> Attribute '$constraint' doesn't exist!");
                }
            }
        }
        $batch = array();
	$batch['to']          = $emailto;
	$batch['subject']     = $emailsubject;
        $batch['maxcolumns']  = $maxcolumns;
	$batch['constraints'] = $constraintargs; 
        $batch['errors']      = $errors;
        $batch['tables']      = $tables;
        $batch['tablecount']  = $tablecount;
	$batch['idallow']     = $this->conformList($this->getConf('conformAllow'));
        return $batch;
    }

    function conformTemplateLineParse($line)
    {
        $args = array();
        $inQuote = FALSE;
        for(  $i = 1 ; $i <= strlen($line); $i++  )
        {
            if( $line{$i} == '"' )
            {
                if($inQuote)
                {
                    array_push($args, htmlspecialchars($arg));
                    $inQuote = FALSE;
                    $arg = "";
                    continue;
                }
                else
                {
                    $inQuote = TRUE;
                    continue;
                }
            }
            else if ( $line{$i} == ' ' )
            {
                if($inQuote)
                {
                    $arg .= ' ';
                    continue;
                }
                else
                {
                    if ( strlen($arg) < 1 ) continue;
                    array_push($args, htmlspecialchars($arg));
                    $arg = "";
                    continue;
                }
            }
            $arg .= $line{$i};
        }
        if ( strlen($arg) > 0 ) array_push($args, htmlspecialchars($arg));
        return $args;
    }

    function conformTablesCreate(&$tables, $tablecount, $tablemode)
    {
        $tables[$tablecount]['mode'] = $tablemode;
        $tables[$tablecount]['args'] = array();
    }

    function conformList($list)
    {
        $values      = explode(',', $list);
        $cleanvalues = array();
        foreach ( $values as $value )
        {
            array_push($cleanvalues, trim($value));
        }
        return $cleanvalues;
    }

}
