/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
//
// bool-proc.c
//
// specialized markup processors
//
// Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
// granted by the author.  No warranties are made on the fitness of this
// source code.
//
*/

#include "while-proc.h"

#include "defs.h"
#include "def-proc.h"
#include "htp-files.h"
#include "macro.h"

BOOL ConditionValue(TASK *task, HTML_ATTRIBUTE *attrib, BOOL notTagFound) 
{
    char *name;
    int  quotes;
    BOOL changed;
    BOOL condTrue;
    const char* value;
    char *attribValue;
    uint type;

    if (!ExpandMacrosInString(task, attrib->name, &name, 
                              &quotes, &changed)) {
        return ERROR;
    }

    HtpMsg(MSG_INFO, task->infile, "while loop check %s", name);
    /* get the macros associated value (NULL if macro not defined) */
    if((value = GetVariableValue(task->varstore, name)) != NULL)
    {
        type = GetVariableType(task->varstore, name);
    }
    else
    {
        type = VAR_TYPE_SET_MACRO;
    }

    if (changed)
        FreeMemory(name);

    /* if only a name is specified, only care if macro is defined */
    if(attrib->value == NULL)
    {
        condTrue = (value != NULL) ? TRUE : FALSE;
    }
    else
    {
        /* macro value comparison */
        if(type == VAR_TYPE_SET_MACRO)
        {
            /* macro comparison (case-sensitive) */
            if (!ExpandMacrosInString(task, attrib->value, &attribValue, 
                                      &quotes, &changed))
            {
                return ERROR;
            }
            
            condTrue = (value != NULL && strcmp(value, attribValue) == 0);
            
            if (changed)
                FreeMemory(attribValue);
        }
        else
        {
            /* block macro, comparisons not allowed */
            condTrue = FALSE;
        }
    }

    /* reverse conditional if NOT attribute found */
    if(notTagFound == TRUE)
    {
        condTrue = (condTrue == TRUE) ? FALSE : TRUE;
    }

    return condTrue;
}


BOOL ProcessWhileBlock(TASK *task, STREAM* blockStream)
{
    TASK newTask;
    BOOL result;

    HtpMsg(MSG_INFO, task->infile, "expanding WHILE loop");

    /* build a new task structure */
    newTask.infile = blockStream;
    newTask.outfile = task->outfile;
    newTask.sourceFilename = task->sourceFilename;
    newTask.varstore = task->varstore;

    /* process the new input file */
    result = ProcessTask(&newTask);
    CloseStream(blockStream);

    return result;
}

uint WhileProcessor(TASK *task, HTML_MARKUP *htmlMarkup, char **newPlaintext)
{
    static uint whileLevel = 0;
    BOOL condTrue;
    BOOL notTagFound;
    STREAM blockFile;
    STREAM inFile;
    HTML_ATTRIBUTE *attrib;

    UNREF_PARAM(newPlaintext);

    condTrue = FALSE;

    /* conditionalLevel keeps track of boolean depth */
    if(whileLevel == 0)
    {
        if((IsMarkupTag(htmlMarkup, "/WHILE")))
        {
            HtpMsg(MSG_ERROR, task->infile, "while block must start with WHILE tag");
            return MARKUP_ERROR;
        }
    }

    if(IsMarkupTag(htmlMarkup, "WHILE"))
    {
        whileLevel++;
        /* this is an ugly way to handle the IF-IF NOT test, but will need */
        /* be cleaned up in the future */

        notTagFound = UnlinkBoolAttributeInMarkup(htmlMarkup, "NOT");

        /* should  be exactly one remaining attribute in markup */
        attrib = htmlMarkup->attrib;
        if (attrib == NULL)
        {
            HtpMsg(MSG_ERROR, task->infile, "no conditional to test");
            return MARKUP_ERROR;
        }

        if(attrib->next != NULL)
        {
            HtpMsg(MSG_ERROR, task->infile, "too many items in conditional expression");
            return MARKUP_ERROR;
        }
        htmlMarkup->attrib = NULL;

        condTrue = ConditionValue(task, attrib, notTagFound);
        if (condTrue == ERROR) {
            DestroyAttribute(attrib);
            FreeMemory(attrib);
            return MARKUP_ERROR;
        }

        if(ReadinBlock(task, htmlMarkup, &blockFile) == FALSE)
        {
            DestroyAttribute(attrib);
            FreeMemory(attrib);
            return MARKUP_ERROR;
        }

        while (condTrue) {
            /* condition is true, so we have to expand the block */
            CreateBufferReader(&inFile, &blockFile);
            if(! ProcessWhileBlock(task, &inFile)) {
                CloseStream(&blockFile);
                DestroyAttribute(attrib);
                FreeMemory(attrib);
                return MARKUP_ERROR;
            }

            /* check condition */
            condTrue = ConditionValue(task, attrib, notTagFound);
            if (condTrue == ERROR) {
                CloseStream(&blockFile);
                DestroyAttribute(attrib);
                FreeMemory(attrib);
                return MARKUP_ERROR;
            }
        }

        CloseStream(&blockFile);
        DestroyAttribute(attrib);
        FreeMemory(attrib);
        return DISCARD_MARKUP;

    }
    else
    {
        /* end of while */
        assert(whileLevel > 0);
        whileLevel--;
    }

    return DISCARD_MARKUP;
}   

