#include <xml/pcss-proc.h>
#include <xml/pcss-src.h>
#include <xml/pdoc-cpp.h>
#include <xml/nextpcre.h>
#include <xml/savetree.h>
#include <xml/addsnode.h>
#include <xml/nextnode.h>
#include <xml/listnode.h>
#include <xml/copynode.h>
#include <xml/attrnode.h>
#include <string.h>
#include <stdlib.h>


#define ___ {
#define ____ }

xml_GNode*
xml_pcss_proc (xml_GNode* tree, xml_GNode* css)
{
    return tree;
}
/* ----------------------------------------------------------------------
   scan the input tree for <prop_head> elements followed by
   some <cblock> containing <prop_value> elements. Build a new
   xm-tree from it containing just the <prop_head> with its
   attributes and has the <prop_value>s as children. This is
   merily list-style tree ready to be used for pcss processing.
 */
xml_GNode*
xml_pcss_prop_list_from (xml_GNode* tree)
{
    xml_GList* list = xml_path_node_to_list (tree, "//prop_head", 0);
    xml_GNode* into = xml_g_node_new (0); /* unnamed */
    into->text = g_string_new (0);
    for (; list ; list = xml_g_list_free_head (list))
    
{
	g_string_append_c (into->text, '\n');
	___ xml_GNode* node = xml_node_append_copy (into, list->data.node, 0);
	node->off--;
	xml_node_rename (node, "prop_rule");
	xml_node_add_new (node, "prop_head", node->off+1, node->end);
	g_string_append_c (into->text, '\n');
	___ xml_GNode* data = list->data.node;
	while (xml_node_hasnextnode_eq_(data, "br") ||
	       xml_node_hasnextnode_as_(data, "*comment")) 
	
{ data = data->next; }
if (xml_node_hasnextnode_as_(data, "*cblock"))
{
	    xml_GList* vals = xml_path_node_list (data->next, "//prop_value");
	    for (; vals ; vals = xml_g_list_free_head (vals))
	    
{
		xml_node_append_copy (node, vals->data.node, 0);
		g_string_append_c (into->text, '\n');
	    }
}
; ____; node->end = into->text->len; ____; g_string_append_c (into->text, '\n'); into->end = into->text->len; }
return into; }
xml_GNode* /* prop_value-node from rule-node */
xml_pcss_prop_rule_attribute_find (xml_GNode* rule, const gchar* name)
{
    /* we know that <prop_value>s are direct children of <prop_rule> */
    if (! rule || ! name || ! rule->children) return 0;
    ___ xml_GNode* node = rule->children;
    for (; node ; node = node->next)
    
{
	if (! xml_node_hasname_eq_(node, "prop_value")) continue;
	___ const gchar* prop = xml_node_attribute_lookup (node, "prop");
	if (! prop || ! xml_test_name_ (prop, name)) continue;
        break; ____;
    }
return node; ____; }
gchar* /* prop_value's value from rule-node */
xml_pcss_prop_rule_attribute_strdup (xml_GNode* rule, const gchar* name)
{
    xml_GNode* prop = xml_pcss_prop_rule_attribute_find (rule, name);
    if (! prop || !prop->text) return 0;
    ___ gchar* val = g_strndup (prop->text->str + prop->off,
				prop->end - prop->off);
    return val;
    ____;
}
/* ----------------------------------------------------------------------
   let's go - use the css rules...
 */
xml_GNode* /* the pcss-rule that did apply */
xml_pcss_rename_rule (xml_GNode* node, xml_GNode* pcss)
{
    xml_GNode* rule = pcss->children;
    for (; rule ; rule = rule->next)
    
{
	gchar* prop = xml_node_attribute_lookup (rule, "class");
	if (! prop || ! xml_node_hasname_eq_(node, prop)) continue;

	/* okay, so we have a rule that matches in class - now check asserts */

	prop = xml_node_attribute_lookup (rule, "when-id");
	if (prop)
	
{
	    gchar* id = xml_node_attribute_lookup (node, "id");
	    if (! id ) continue;
	    if (! xml_test_name_eq_(id, prop+1)) continue;
	}
prop = xml_node_attribute_lookup (rule, "when-after"); if (prop)
{
	    if (! node->prev || !node->prev->name) continue;
	    if (! xml_node_hasname_eq_ (node->prev, prop)) continue;
	}
prop = xml_node_attribute_lookup (rule, "when-childof"); if (prop)
{
	    if (! node->parent || !node->parent->name) continue;
	    if (! xml_node_hasname_eq_ (node->parent, prop)) continue;
	}
prop = xml_node_attribute_lookup (rule, "when-inside"); if (prop)
{
	    xml_GNode* seen = node->parent;
	    for (; seen ; seen = seen->parent)
	    
{
		if (xml_node_hasname_eq_ (seen, prop)) break;
	    }
if (! seen) continue; }
break; }
return rule; }
void 
xml_pcss_rename_func_to_xml (xml_GNode* node, xml_GNode* rule, gpointer data)
{
    gchar* prop = xml_node_attribute_lookup (rule, "mark");
    if (prop) 
{
	xml_node_rename (node, prop);
    }
else if (data)
{
	if (! xml_node_hasname_eq_ (node, data))
	    xml_node_attribute_add (node, "class", node->name);
	xml_node_rename (node, data);
    }
}
static xml_GNode*
add_table_attributes (xml_GNode* node, xml_GNode* rule)
{
    /* these are largely for Netscape4 compatibility */
    if (! node) return node;
    ___ gchar* val;
    val = xml_pcss_prop_rule_attribute_strdup (
        rule, "width"); if (! val) val = g_strdup ("100%");
    if (val)
        xml_node_attribute_add_value (node, "width", val);
    val = xml_pcss_prop_rule_attribute_strdup (
        rule, "background-color");
    if (val)
        xml_node_attribute_add_value (node, "bgcolor", val);
    val = xml_pcss_prop_rule_attribute_strdup (
        rule, "border-spacing");
    if (val)
        xml_node_attribute_add_value (node, "cellspacing", val);
    ____;
    return node;
}
void 
xml_pcss_rename_func_to_html (xml_GNode* node, xml_GNode* rule, gpointer data)
{
    gchar* mrkk = 0;
    const gchar* mark = xml_node_attribute_lookup (rule, "mark");
    if (! mark)
    
{
        if (! mrkk)
            mrkk = xml_pcss_prop_rule_attribute_strdup (rule, "html");
        if (! mrkk)
            mrkk = xml_pcss_prop_rule_attribute_strdup (rule, "into");
        if (! mrkk)
            mrkk = xml_pcss_prop_rule_attribute_strdup (rule, "mark");
        if (mrkk) mark = mrkk;
    }
___ gchar* prop = xml_pcss_prop_rule_attribute_strdup (rule, "display"); if (prop)
{
        if (! strcmp (prop, "block") || ! strcmp (prop, "div"))
        
{
            if (! mark)
                mark = "div";
            else
                xml_node_group_outer_alias (node, "div");
        }
else if (! strcmp (prop, "list-item") || ! strcmp (prop, "li"))
{
            xml_node_attribute_add (
                xml_node_group_outer_alias (node, "li"),
		    "class", node->name);
            /* mark = "span" */
        }
else if (! strcmp (prop, "table-row") || ! strcmp (prop, "tr"))
{
            if (! mark)
                mark = "tr";
            else
                xml_node_group_outer_alias (node, "tr");
        }
else if (! strcmp (prop, "table-cell") || ! strcmp (prop, "td"))
{
            if (! mark)
                mark = "td";
            else
                xml_node_group_outer_alias (node, "td");
        }
else if (! strcmp (prop, "table"))
{
            if (! mark)
                mark = "table";
            else
                add_table_attributes ( 
                    xml_node_group_outer_alias (node, "table"), rule);
        }
else if (! strcmp (prop, "inline-table") || ! strcmp (prop, "li"))
{
            xml_node_attribute_add ( 
                add_table_attributes (
                    xml_node_group_outer_alias (node, "table"), rule),
                "class", node->name);
            xml_node_attribute_add (
                xml_node_group_outer_alias (node, "tr"),
                "class", node->name);
            xml_node_attribute_add (
                xml_node_group_outer_alias (node, "td"),
                "class", node->name);
            /* mark = "span" */
        }
}
if (! mark) mark = "span"; /* we have a number of specials around */ if (!strcmp (mark, "a"))
{
        if (prop) g_free (prop);
	prop = xml_pcss_prop_rule_attribute_strdup (rule, "name");
	if (prop)
	
{
	    gchar* key;
	    gchar* val = xml_node_attribute_lookup (node, prop);

	    if (val && ! xml_node_attribute_lookup (node, "name"))
	    
{ /* w3.org/xhtml1/#C.8 Fragment Identifiers :
	       * When defining fragment identifiers to be backward-compatible, 
	       * only strings matching the pattern [A-Za-z][A-Za-z0-9:_.-]* 
	       * should be used. See Section 6.2 of [HTML4] for more.
	       *
	       */
		val = g_strdup (val);
		for (key = val ; *key ; key++) 
		
{
		    if (g_ascii_isalnum (*key)) continue;
		    if (!strchr (":_-.", *key)) *key = ':';
		    if (key == val) continue;
		    if (key[0] == '.' && key[-1] == '.')
		    
{ strcpy (key-1, key); key--; }
if (key[0] == ':' && key[-1] == '.')
{ strcpy (key-1, key); key--; }
}
key = g_strdup ("name"); xml_node_attribute_insert (node, key, val); }
/* w3.org/xhtml1/#C.8 Fragment Identifiers : * Many existing HTML clients don't support the use of ID-type * attributes in this way, so identical values may be supplied * for both of these attributes to ensure maximum forward and * backward compatibility (e.g. <a id="foo" name="foo">...</a>). */ val = xml_node_attribute_lookup (node, "name"); if (val)
{
		if (!xml_node_attribute_lookup (node, "id"))
		    xml_node_attribute_add (node, "id", val);
	    }
}
}
else if (!strcmp (mark, "table"))
{
        add_table_attributes (node, rule);
    }
if (prop) g_free (prop); ____; if (! xml_node_hasname_eq_ (node, mark)) xml_node_attribute_add (node, "class", node->name); xml_node_rename (node, mark); if (mrkk) g_free (mrkk); }
xml_GNode* /* the pcss-rule that did apply */
xml_pcss_rename_node_with (xml_GNode* node, xml_GNode* pcss, 
			   xml_NodeRenameFunc func, gpointer data)
{
    xml_GNode* rule = xml_pcss_rename_rule (node, pcss);
    if (! rule || ! func) return rule;
    func (node, rule, data);
    return rule;
}
void
xml_pcss_rename_children (xml_GNode* tree, xml_GNode* pcss, 
			  xml_NodeRenameFunc func, gpointer data)
{
    if (! tree) return;
    
    ___ xml_GNode* next; xml_GNode* node = tree->children;
    for (; node ; node = next)
    
{
	next = node->next;
	/* [a] rename parent(s) [b] elder brother(s) [c] this node [d] ... */
	xml_pcss_rename_node_with (node, pcss, func, data);
	xml_pcss_rename_children (node, pcss, func, data);
    }
____; }
xml_GNode*
xml_pcss_rename_proc (xml_GNode* tree, xml_GNode* css, gchar* mark_def)
{
    xml_NodeRenameFunc func = ( mark_def )
	? xml_pcss_rename_func_to_xml : xml_pcss_rename_func_to_html ;
    xml_GNode* pcss;
    xml_pcss_tree_scan_selectors (css);
    pcss = xml_pcss_prop_list_from (css);
    xml_pcss_rename_children (tree, pcss, func, mark_def);
    return tree;
}
/* 
   Local variables:
   c-file-style: "stroustrup"
   End:
 */