<?php
if (!defined('STANDALONE'))
{
    
define('STANDALONE','STANDALONE'.time());
}
require_once(
'fishargs.class.php');
class 
FishHTML
{

    function 
get_attlist($args=array(),$allowed=array())
    {
        static 
$collections NULL;
        static 
$collection_keys NULL;
        if (
$collections === NULL)
        {
            
$collections = array(
                
'Core' => array('class','id','title')
                , 
'I18N' => array('xml:lang')
                , 
'Events' => array('onclick','ondblclick','onmousedown'
                    
,'onmouseup','onmouseover','onmousemove','onmouseout'
                    
,'onkeypress','onkeydown','onkeyup'
                
)
                , 
'Style' => array('style')
            );
            
$collections['Common'] = array_merge(
                
$collections['Core']
                , 
$collections['Events']
                , 
$collections['I18N']
                , 
$collections['Style']
            );
            
$collection_keys array_keys($collections);
        }

        
$args = (array)$args;
        
$allowed = (array)$allowed;

        if (empty(
$allowed))
        {
            
$allowed FishUtil::array_key_value($args,'allowed',$collections['Common']);
        }
        
$match_keys array_intersect($allowed,$collection_keys);
        foreach (
$match_keys as $k => $v)
        {
            
array_splice($allowed$k1$collections[$v]);
        }
        
FishUtil::array_key_remove($argsarray_diff(array_keys($args),$allowed));

        
$output '';
        foreach (
$args as $k => $v)
        {
            if (
$v === NULL)
            {
                continue;
            }
//            FishError::trace('k=', $k, ' v=', $v);
            
$output .= ' '.$k;
            if (
$v !== STANDALONE)
            {
                
$output .= '="'.$v.'"';
            }
        }
        return 
$output;
    }



    
// string title_tag ([string src [,array attributes]])

    // This function returns an HTML image tag (<img>). The first argument
    // gives theURL of the image to be displayed. Additional attributes
    // may be supplied as an array in the third argument.

    
function title_tag()
    {
        static 
$_defaults = array(
            
'title' => 'Example'
            
'value' => '$title'
            
'allowed' => array('I18N')
        );
        static 
$_simple = array('title');

        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);

        require_once(
'fishtext.class.php');
        
$title FishText::make_page_title($p['title']);
        
$output "<title $attlist>$title</title>";
        return 
$output;
    }



    
// string head_tag ([string src [,array attributes]])

    // This function returns an HTML image tag (<img>). The first argument
    // gives theURL of the image to be displayed. Additional attributes
    // may be supplied as an array in the third argument.

    
function head_tag()
    {
        static 
$_defaults = array(
            
'contents' => ''
            
'allowed' => array('I18N','profile')
        );
        static 
$_simple = array();
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        if (
stristr($p['contents'],'<title') === FALSE)
        {
            
$p['contents'] .= "\n".FishHTML::title_tag($p)."\n";
        }

        
$output = <<<EOQ
<head $attlist>
{$p['contents']}
</head>
EOQ;
        return 
$output;
    }



    
// string body_tag ([string src [,array attributes]])

    // This function returns an HTML image tag (<img>). The first argument
    // gives theURL of the image to be displayed. Additional attributes
    // may be supplied as an array in the third argument.

    
function body_tag()
    {
        static 
$_defaults = array(
            
'bgcolor' => '#FFFFFF'
            
'allowed' => array('Common','onload','onunload','link','alink'
                
,'vlink','text','background','bgcolor'
            
)
        );
        static 
$_simple = array();
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "<body $attlist>";

        return 
$output;
    }



    
// string page_title ([string text of page title])

    // This function returns an HTML <h2> tag. It is used for the titles
    // of pages in our examples. The reason to 
    // display these via a function, rather than just literal <h2> tags,
    // is to enable you to change the format of in one
    // place, instead of in each script.

    
function page_title($what='')
    {
        return 
"<h2>$what</h2>\n";
    }



    function 
start_page()
    {
        static 
$_defaults = array(
            
'title' => NULL
        
);
        static 
$_simple = array('title');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
extract($p);
        if (
array_key_exists('_defaults'$p))
            unset(
$p['_defaults']);
        if (
array_key_exists('_simple'$p))
            unset(
$p['_simple']);
        
$head FishHTML::head_tag($p);
        if (
array_key_exists('title'$p))
            unset(
$p['title']);
        
$body FishHTML::body_tag($p);
        if (!isset(
$page_header))
        {
            
$page_header FishHTML::page_title($title);
        }

        
$output '';
        if (!@include(
'start_page.php'))
        {
            
$output = <<<EOQ
<html>
$head
$body
$page_header

EOQ;
        }
        return 
$output;
    }

    function 
default_end_page()
    {
        
$output = <<<EOQ
</body>
</html>
EOQ;
        return 
$output;
    }

    function 
end_page()
    {
        
$output NULL;
        
$default_file realpath(dirname(__FILE__).'/end_page.php');
        if (!@include(
'end_page.php'))
        {
            if (
file_exists($default_file))
            {
                include(
$default_file);
            }
            else
            {
                
$output FishHTML::default_end_page();
            }
        }
        return 
$output;
    }

    
// string anchor_tag ([string href [, string text [, array attributes]]])

    // This function returns an HTML anchor tag (<a>).  The first argument
    // be the URL to which the tag points, and the second argument will
    // be the text of the tag. Additional attributes may be supplied as
    // an array in the third argument.

    
function anchor_tag()
    {
        static 
$_defaults = array(
            
'href'=>''
            
'text' => ''
            
'value' => ''
            
'allowed' => array('Common','accesskey','charset','href'
                
,'hreflang','rel','rev','tabindex','type','name','target'
            
)
        );
        static 
$_simple = array('href','value');

        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);

        if (empty(
$p['text']))
        {
            
$p['text'] = $p['href'];
        }
        if (empty(
$p['value']))
        {
            
$p['value'] = $p['text'];
        }
        
        
$attlist FishHTML::get_attlist($p);

        
$output "<a $attlist>{$p['value']}</a>";

        return 
$output;
    }

    
// string font_tag ([int size [, string typeface [, array attributes]]])

    // This function returns an HTML <font> tag. The default font size is
    // 2, and the default font typeface is sans-serif. Additional attributes
    // for the tag may be supplied as an array in the third argument.

    
function font_tag()
    {
        static 
$_defaults = array(
            
'size' => 2
            
'face' => 'sans-serif'
            
'allowed' => array('Common','color','face','size')
        );
        static 
$_simple = array('size');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "<font $attlist>";

        return 
$output;
    }

    
// string image_tag ([string src [,array attributes]])

    // This function returns an HTML image tag (<img>). The first argument
    // gives theURL of the image to be displayed. Additional attributes
    // may be supplied as an array in the third argument.

    
function image_tag()
    {
        static 
$_defaults = array(
            
'src' => ''
            
'alt' => ''
            
'border' => 0
            
'allowed' => array('Common','alt','height','width','longdesc'
                
,'src','usemap','ismap','name','align','border','hspace','vspace'
            
)
        );
        static 
$_simple = array('src');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "<img $attlist />";

        return 
$output;
    }

    function 
start_paragraph()
    {
        
$p func_get_args();
        
$p[] = array('start'=>'yes');
        return 
call_user_func_array(array('FishHTML','paragraph'), $p);
    }

    function 
end_paragraph()
    {
        
$output "\n</p>\n";
        return 
$output;
    }

    
// string paragraph ([array attributes [, mixed ...]])

    // This function will return a string inside HTML paragraph (<p>) tags.
    // Attributes for the <p> tag may be supplied in the first argument.
    // Any additional arguments will be included inside the opening and
    // closing <p> tags, separated by newlines.

    
function paragraph()
    {
        static 
$_defaults = array(
            
'values' => array()
            , 
'allowed' => array('Common','align')
            , 
'start' => NULL
        
);
        static 
$_simple = array('values');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);

        
$output "\n<p $attlist>\n";
        if (
$p['start'] !== NULL)
        {
            return 
$output;
        }
        
$output .= implode("\n",(array)$p['values'])
            .
FishHTML::end_paragraph($p)
        ;
        return 
$output;
    }

    
// string subtitle ([string text of subtitle])

    // This function returns an HTML <h3> tag. It is used for the titles
    // of secondary areas within pages in our examples. The reason to 
    // display these via a function, rather than just literal <h3> tags,
    // is to enable you to change the format of these subtitles in one
    // place, instead of in each script.

    
function subtitle($what='')
    {
        return 
"<h3>$what</h3>\n";
    }

    function 
li_tag()
    {
        static 
$_defaults = array(
            
'text' => ''
            
'allowed' => array('Common','type','value')
        );
        static 
$_simple = array('text');

        
$p func_get_args();
//        FishError::trace('before parse: p=', $p);
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
//        FishError::trace('after parse: p=', $p);
        
$attlist FishHTML::get_attlist($p);

        if (
is_array($p['text']) or is_object($p['text']))
        {
            
$p['text'] = implode('',(array)$p['text']);
        }

        
$output " <li $attlist>{$p['text']}</li>\n";
        return 
$output;
    }

    function 
ul_list()
    {
        static 
$_defaults = array(
            
'values' => array()
            , 
'contents' => NULL
            
'allowed' => array('Common','compact','type')
        );
        static 
$_simple = array('values');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);

        
$output "<ul $attlist>\n";

        if (!empty(
$p['values']) 
            && !
is_array($p['values']) 
            && !
is_object($p['values'])
        )
        {
            
$output .= $p['values'];
        }
        else
        {
            if (
array_key_exists('_defaults'$p))
                unset(
$p['_defaults']);
            if (
array_key_exists('_simple'$p))
                unset(
$p['_simple']);
            if (
array_key_exists('allowed'$p))
                unset(
$p['allowed']);
            foreach (
$p['values'] as $p['text'])
            {
                
$output .= FishHTML::li_tag($p);
            }
        }
        
$output .= $p['contents'];
        
$output .= "</ul>\n";
        return 
$output;
    }

    
// string table_cell ([string value [, array attributes]])

    // This function returns an HTML table cell (<td>) tag. The first
    // argument will be used as the value of the tag. Attributes for the
    // <td> tag may be supplied as an array in the second argument.
    // By default, the table cell will be aligned left horizontally,
    // and to the top vertically.

    
function table_cell()
    {
        static 
$_defaults = array(
            
'align' => 'left'
            
'valign' => 'top'
            
'value' => ''
            
'allowed' => array('Common','abbr','align','axis','char','charoff'    
                
,'colspan','headers','rowspan','scope','valign','width','height'    
                
,'nowrap','bgcolor'
            
)
        );
        static 
$_simple = array('value');

        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);

        if (
is_array($p['value']) or is_object($p['value']))
        {
            
$p['value'] = implode('',(array)$p['value']);
        }

        
$output "\n  <td $attlist>{$p['value']}</td>\n";
        return 
$output;
    }

    
// string table_row ([mixed ...])

    // This function returns an HTML table row (<tr>) tag, enclosing a variable
    // number of table cell (<td>) tags. If any of the arguments to the function
    // is an array, it will be used as attributes for the <tr> tag. All other
    // arguments will be used as values for the cells of the row. If an
    // argument begins with a <td> tag, the argument is added to the row as is.
    // Otherwise it is passed to the table_cell() function and the resulting
    // string is added to the row.

    
function table_row()
    {
        static 
$_defaults = array(
            
'cells' => array()
            , 
'allowed' => array('Common','align','valign','char','charoff'
                
,'bgcolor'
            
)
        );
        static 
$_simple = array('cells');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "\n <tr $attlist>\n";
        foreach ((array)
$p['cells'] as $cell)
        {
            if (!
preg_match('/<t[dh]/i'$cell))
            {
                
$output .= FishHTML::table_cell($cell);
            }
            else
            {
                
$output .= $cell;
            }
        }
        
$output .= "\n </tr>\n";
        return 
$output;
    }

    
// string table_header_cell ([string value [, array attributes]])

    // This function returns an HTML table header cell (<th>) tag. The first
    // argument will be used as the value of the tag. Attributes for the
    // <td> tag may be supplied as an array in the second argument.
    // By default, the table cell will be aligned left horizontally,
    // and to the top vertically.

    
function table_header_cell()
    {
        static 
$_defaults = array(
            
'align' => 'left'
            
'valign' => 'top'
            
'value' => ''
            
'allowed' => array('Common','abbr','align','axis','char','charoff'    
                
,'colspan','headers','rowspan','scope','valign','width','height'    
                
,'nowrap','bgcolor'
            
)
        );
        static 
$_simple = array('value');

        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);

        if (
is_array($p['value']) or is_object($p['value']))
        {
            
$p['value'] = implode('',(array)$p['value']);
        }

        
$output "\n  <th $attlist>{$p['value']}</th>\n";
        return 
$output;
    }

    
// string table_header_row ([mixed ...])

    // This function returns an HTML table row (<tr>) tag, enclosing a variable
    // number of table cell (<td>) tags. If any of the arguments to the function
    // is an array, it will be used as attributes for the <tr> tag. All other
    // arguments will be used as values for the cells of the row. If an
    // argument begins with a <td> tag, the argument is added to the row as is.
    // Otherwise it is passed to the table_header_cell() function and the resulting
    // string is added to the row.

    
function table_header_row()
    {
        static 
$_defaults = array(
            
'cells' => array()
            , 
'allowed' => array('Common','align','valign','char','charoff'
                
,'bgcolor'
            
)
        );
        static 
$_simple = array('cells');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "\n <tr $attlist>\n";
        foreach ((array)
$p['cells'] as $cell)
        {
            if (
stristr($cell,'<td') === FALSE && stristr($cell,'<th') === FALSE)
            {
                
$output .= FishHTML::table_header_cell($cell);
            }
            else
            {
                
$output .= $cell;
            }
        }
        
$output .= "\n </tr>\n";
        return 
$output;
    }

    
// string end_table (void)
    // This function returns a closing <table> tag.

    
function end_table()
    {
        
$output "\n</table>\n";
        return 
$output;
    }

    
// string start_table ([array attributes])
    // This function returns an opening HTML <table> tag.
    // Attributes for the table may be supplied 
    // as an array.

    
function start_table()
    {
        static 
$_defaults = array(
            
'cellspacing' => 0
            
'cellpadding' => 1
            
'allowed' => array('Common','border','cellpadding','cellspacing'
                
,'datapagesize','frame','rules','summary','width','align','bgcolor'
            
)
        );
        static 
$_simple = array('width');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);
        
$attlist FishHTML::get_attlist($p);
        
$output "\n<table $attlist>\n";
        return 
$output;
    }

    function 
table()
    {
        static 
$_defaults = array(
            
'rows' => array()
        );
        static 
$_simple = array('rows');
        
$p func_get_args();
        
$p FishArgs::parse_arguments($p$_simple$_defaults);

        
$output FishHTML::start_table($p);

        foreach ((array)
$p['rows'] as $row)
        {
            
$output .= FishHTML::table_row($row);
        }

        
$output .= FishHTML::end_table($p);

        return 
$output;
    }

    function 
hashlist_table()
    {
        static 
$_defaults = array(
            
'rows' => array()
            , 
'pad' => ''
        
);
        static 
$_simple = array('rows');
        
$args func_get_args();
        
$p FishArgs::parse_arguments($args$_simple$_defaults);

        if (!
is_array($p['rows']) or count($p['rows']) == 0)
            return;

        
$output FishHTML::start_table($p);
        
$keys = array();
        
$i 0;
        foreach (
$p['rows'] as $row)
        {
            if (!
FishUtil::is_assoc($row))
                continue;
            if (!
$i++)
            {
                
$keys array_keys($row);
                
$output .= FishHTML::table_header_row($keys);
            }
            
$o = array();
            foreach (
$keys as $k)
            {
                if (isset(
$row[$k]))
                {
                    
$v $row[$k];
                }
                else
                {
                    
$v '';
                }
                
$o[] = $v.$p['pad'];
            }
            
$output .= FishHTML::table_row($o);
        }
        
$output .= FishHTML::end_table($p);
        return 
$output;
    }

    function 
labeled_row($label=NULL,$value=NULL)
    {
        return 
FishHTML::table_row(FishHTML::table_header_cell($label), FishHTML::table_cell($value));
    }
}
?>