/* AbiSource Program Utilities
 * 
 * Copyright (C) 2005 Daniel d'Andrada T. de Carvalho
 * <daniel.carvalho@indt.org.br>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
// Class definition include
#include "ODi_ListLevelStyle.h"

// Internal includes
#include "ODi_ListenerStateAction.h"
#include "ODi_Style_Style.h"

// AbiWord includes
#include <pd_Document.h>
#include <fp_types.h>
#include <ut_string_class.h>
#include <ut_units.h>
#include <ut_locale.h>

//External includes
#include <stdlib.h>


/**
 * Constructor
 */
ODi_ListLevelStyle::ODi_ListLevelStyle(const char* pStateName,
									 ODi_ElementStack& rElementStack) :
                        ODi_ListenerState(pStateName, rElementStack),
                        m_pTextStyle(NULL)
{
}


/**
 * 
 */
void ODi_ListLevelStyle::startElement (const XML_Char* pName,
                                      const XML_Char** ppAtts,
                                      ODi_ListenerStateAction& rAction) {
    const XML_Char* pVal = NULL;

    if (!UT_strcmp("text:list-level-style-bullet", pName) ||
        !UT_strcmp("text:list-level-style-number", pName) ||
        !UT_strcmp("text:list-level-style-image", pName)) {

        UT_uint32 result;
            
        pVal = UT_getAttribute ("text:level", ppAtts);
        UT_ASSERT(pVal);
        
        result = sscanf(pVal, "%u", &m_levelNumber);
        UT_ASSERT(result==1);
        m_level = pVal;
        
        pVal = UT_getAttribute ("text:style-name", ppAtts);
        if (pVal) {
            m_textStyleName = pVal;
        }
        
    } else if (!UT_strcmp("style:list-level-properties", pName)) {

        pVal = UT_getAttribute ("text:space-before", ppAtts);
        if (pVal) {
            m_spaceBefore = pVal;
        } else {
            m_spaceBefore = "0cm";
        }
        
        pVal = UT_getAttribute ("text:min-label-width", ppAtts);
        if (pVal) {
            m_minLabelWidth = pVal;
        } else {
            m_minLabelWidth = "0cm";
        }
        
        pVal = UT_getAttribute ("text:min-label-distance", ppAtts);
        if (pVal) {
            m_minLabelDistance = pVal;
        }
    }
}


/**
 * 
 */
void ODi_ListLevelStyle::endElement (const XML_Char* pName,
                                    ODi_ListenerStateAction& rAction) {
                                        
    if (!UT_strcmp("text:list-level-style-bullet", pName) ||
        !UT_strcmp("text:list-level-style-number", pName) ||
        !UT_strcmp("text:list-level-style-image", pName)) {
            
        // We're done.
        rAction.popState();
    }
}


/**
 * 
 */
void ODi_ListLevelStyle::setAbiListID(UT_uint32 abiListID) {
    XML_Char buffer[100];
    
    sprintf(buffer, "%u", abiListID);
    m_abiListID.assign(buffer);
}


/**
 * Defines a <l> tag on the AbiWord document corresponding to this
 * list level style.
 */
void ODi_ListLevelStyle::defineAbiList(PD_Document* pDocument) {
    const XML_Char* ppAttr[13];
    
    ppAttr[0] = "id";
    ppAttr[1] = m_abiListID.utf8_str();
    ppAttr[2] = "parentid";
    ppAttr[3] = m_abiListParentID.utf8_str();
    ppAttr[4] = "type";
    ppAttr[5] = m_abiListType.utf8_str();
    ppAttr[6] = "start-value";
    ppAttr[7] = m_abiListStartValue.utf8_str();
    ppAttr[8] = "list-delim";
    ppAttr[9] = m_abiListListDelim.utf8_str();
    ppAttr[10] = "list-decimal";
    ppAttr[11] = m_abiListListDecimal.utf8_str();
    ppAttr[12] = 0;
    
    pDocument->appendList(ppAttr);
}


/**
 * 
 */
void ODi_ListLevelStyle::buildAbiPropsString() {
    m_abiProperties.clear();
}


/**
 * The AbiWord properties of the list depends on some properties already
 * defined by the AbiWord paragraph style.
 * 
 * @param rProps Will have the properties string appended.
 * @param pStyle Pointer to the paragraph style used on this list paragraph.
 */    
void ODi_ListLevelStyle::getAbiProperties(UT_UTF8String& rProps,
                                         const ODi_Style_Style* pStyle) const {

    // Adds the fixed portion of the properties.
    if (!m_abiProperties.empty()) {
        if (!rProps.empty()) {
            rProps += "; ";
        }
        rProps += m_abiProperties;
    }
    
    
    // From the OpenDocument OASIS standard, v1.0:
    //
    // "The text:space-before attribute specifies the space to include before
    // the number for all paragraphs at this level. If a paragraph has a left
    // margin that is greater than 0, the actual position of the list label box
    // is the left margin width plus the start indent value."
    //
    // AbiWord's margin-left = OpenDocument paragraph property fo:margin-left +
    //                         OpenDocument text:space-before +
    //                         OpenDocument text:min-label-witdh
    //
    // AbiWord's text-indent = - (minus) OpenDocument text:min-label-width
    //

    UT_UTF8String odMarginLeft;

    if (pStyle != NULL &&
        !UT_strcmp(pStyle->getFamily()->utf8_str(), "paragraph")) {

        odMarginLeft = *(pStyle->getMarginLeft());
    } else {
        odMarginLeft = "0.0cm";
    }
    
    double spaceBefore_cm;
    double minLabelWidth_cm;

    double styMarginLeft_cm;
    XML_Char buffer[100];
    UT_LocaleTransactor lt(LC_NUMERIC, "C");
    
    spaceBefore_cm = UT_convertToDimension(m_spaceBefore.utf8_str(),
                                           DIM_CM);
                                           
    minLabelWidth_cm = UT_convertToDimension(m_minLabelWidth.utf8_str(),
                                             DIM_CM);
                                             
    styMarginLeft_cm = UT_convertToDimension(odMarginLeft.utf8_str(),
                                             DIM_CM);
    
    sprintf(buffer, "%fcm", styMarginLeft_cm + spaceBefore_cm + 
                            minLabelWidth_cm);
                            
    if (!rProps.empty()) {
        rProps += "; ";
    }
    rProps += "margin-left:";
    rProps.append(buffer);
    
    sprintf(buffer, "%fcm", -minLabelWidth_cm);

    rProps += "; text-indent:";
    rProps.append(buffer);

    
}


/******************************************************************************/


/**
 * 
 */
ODi_Bullet_ListLevelStyle::ODi_Bullet_ListLevelStyle(ODi_ElementStack& rElementStack)
	: ODi_ListLevelStyle("Bullet_ListLevelStyle", rElementStack)
{
    // Dummy values
    m_abiListStartValue.assign("0");
    m_abiListListDelim.assign("%L");
    m_abiListListDecimal.assign("NULL");
}


/**
 * 
 */
void ODi_Bullet_ListLevelStyle::startElement(const XML_Char* pName,
                                             const XML_Char** ppAtts,
                                             ODi_ListenerStateAction& rAction) {

    const XML_Char* pVal = NULL;
    UT_UCS4String ucs4Str;
    
    // Let the parent class do the processing common to all list types.
    ODi_ListLevelStyle::startElement (pName, ppAtts, rAction);

    if (!UT_strcmp("text:list-level-style-bullet", pName)) {
        pVal = UT_getAttribute ("text:bullet-char", ppAtts);
        
        if (pVal != NULL) {
        
            ucs4Str = pVal;
            
            if (!ucs4Str.empty()) {
                switch (ucs4Str[0]) {
                    case 8226: // U+2022 BULLET
                        // Bullet List
                        UT_UTF8String_sprintf(m_abiListType, "%d", BULLETED_LIST);
                        break;
                        
                    case 8211: // U+2013 EN DASH
                        // Dashed List
                        UT_UTF8String_sprintf(m_abiListType, "%d", DASHED_LIST);
                        break;
                        
                    case 9632: // U+25A0 BLACK SQUARE
                        // Square List
                        UT_UTF8String_sprintf(m_abiListType, "%d", SQUARE_LIST);
                        break;
                        
                    case 9650: // U+25B2 BLACK UP-POINTING TRIANGLE
                        // Triangle List
                        UT_UTF8String_sprintf(m_abiListType, "%d", TRIANGLE_LIST);
                        break;
                    
                    case 9830: // U+2666 BLACK DIAMOND SUIT
                        // Diamond List
                        UT_UTF8String_sprintf(m_abiListType, "%d", DIAMOND_LIST);
                        break;
                        
                    case 10035: // U+2733 EIGHT SPOKED ASTERISK
                        // Star List
                        UT_UTF8String_sprintf(m_abiListType, "%d", STAR_LIST);
                        break;
                        
                    case 10003: // U+2713 CHECK MARK
                        // Tick List
                        UT_UTF8String_sprintf(m_abiListType, "%d", TICK_LIST);
                        break;
                        
                    case 10066: // U+2752 UPPER RIGHT SHADOWED WHITE SQUARE
                        // Box List
                        UT_UTF8String_sprintf(m_abiListType, "%d", BOX_LIST);
                        break;
                        
                    case 9758: // U+261E WHITE RIGHT POINTING INDEX
                        // Hand List
                        UT_UTF8String_sprintf(m_abiListType, "%d", HAND_LIST);
                        break;
                        
                    case 9829: // U+2665 BLACK HEART SUIT
                        // Heart List
                        UT_UTF8String_sprintf(m_abiListType, "%d", HEART_LIST);
                        break;
                        
                    case 8658: // U+21D2 RIGHTWARDS DOUBLE ARROW
                        // Implies List
                        UT_UTF8String_sprintf(m_abiListType, "%d", IMPLIES_LIST);
                        break;
                        
                    default:
                        // Bullet List
                        UT_UTF8String_sprintf(m_abiListType, "%d", BULLETED_LIST);
                };
                
            } // if (!ucs4Str.empty())
        } else /* from if (pVal != NULL) */ {
            // Bullet List
            UT_UTF8String_sprintf(m_abiListType, "%d", BULLETED_LIST);
        }
        
    } else if (!UT_strcmp("text:list-level-style-image", pName)) {
        // Force it into a default Bullet List
        UT_UTF8String_sprintf(m_abiListType, "%d", BULLETED_LIST);
    }
}


/**
 * 
 */
void ODi_Bullet_ListLevelStyle::buildAbiPropsString() {
    
    ODi_ListLevelStyle::buildAbiPropsString();
    
    if (!m_abiProperties.empty()) {
        m_abiProperties += "; ";
    }
    
    m_abiProperties += "list-style:";
    switch (atoi(m_abiListType.utf8_str())) {
        case BULLETED_LIST:
            m_abiProperties += "Bullet List; field-font:Symbol";
            break;
            
        case DASHED_LIST:
            m_abiProperties += "Dashed List; field-font:Symbol";
            break;
            
        case SQUARE_LIST:
            m_abiProperties += "Square List; field-font:Dingbats";
            break;
            
        case TRIANGLE_LIST:
            m_abiProperties += "Triangle List; field-font:Dingbats";
            break;
            
        case DIAMOND_LIST:
            m_abiProperties += "Diamond List; field-font:Dingbats";
            break;
            
        case STAR_LIST:
            m_abiProperties += "Star List; field-font:Dingbats";
            break;
            
        case IMPLIES_LIST:
            m_abiProperties += "Implies List; field-font:Symbol";
            break;
            
        case TICK_LIST:
            m_abiProperties += "Tick List; field-font:Dingbats";
            break;
            
        case BOX_LIST:
            m_abiProperties += "Box List; field-font:Dingbats";
            break;
            
        case HAND_LIST:
            m_abiProperties += "Hand List; field-font:Dingbats";
            break;
            
        case HEART_LIST:
            m_abiProperties += "Heart List; field-font:Dingbats";
            break;
            
        default:
            UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
    }
}


/******************************************************************************/


/**
 * Constructor
 */
ODi_Numbered_ListLevelStyle::ODi_Numbered_ListLevelStyle(ODi_ElementStack& rElementStack)
    : ODi_ListLevelStyle("Numbered_ListLevelStyle", rElementStack) {
        
    // It seens that OpenDocument aways uses a dot "." as level delimiter.
    m_abiListListDecimal = ".";
}


/**
 * 
 */
void ODi_Numbered_ListLevelStyle::startElement (const XML_Char* pName,
                                               const XML_Char** ppAtts,
                                               ODi_ListenerStateAction& rAction) {

    const XML_Char* pVal;

    // Let the parent class do the processing common to all list types.
    ODi_ListLevelStyle::startElement (pName, ppAtts, rAction);
                                                
    if (!UT_strcmp("text:list-level-style-number", pName)) {
        UT_UTF8String prefix, suffix;
        
        pVal = UT_getAttribute ("style:num-format", ppAtts);
        UT_ASSERT(pVal);
        _setAbiListType(pVal);

        if (!UT_strcmp(pVal, "")) {
            // We have an empty number format.
            
            // Empty list label or "invisible" list.
            m_abiListListDelim = "";
            
        } else {
            // We have a number format defined.
            
            pVal = UT_getAttribute ("style:num-prefix", ppAtts);
            if(pVal) {
                prefix = pVal;
            }
            
            pVal = UT_getAttribute ("style:num-suffix", ppAtts);
            if(pVal) {
                suffix = pVal;
            }
            
            m_abiListListDelim  = prefix;
            m_abiListListDelim += "%L";
            m_abiListListDelim += suffix;
        }
        
        pVal = UT_getAttribute ("text:start-value", ppAtts);
        if(pVal) {
            m_abiListStartValue = pVal;
        } else {
            // AbiWord's default value is 0, but on OpenDocument it's 1.
            m_abiListStartValue = "1";
        }
    }
}


/**
 * 
 */
void ODi_Numbered_ListLevelStyle::buildAbiPropsString() {
    
    ODi_ListLevelStyle::buildAbiPropsString();
    
    if (!m_abiProperties.empty()) {
        m_abiProperties += "; ";
    }
    
    m_abiProperties += "field-font: ";
    if (m_pTextStyle) {
        m_abiProperties += *(m_pTextStyle->getFontName());
    } else {
        m_abiProperties += "NULL";
    }
    
    m_abiProperties += "; list-style:";
    switch (atoi(m_abiListType.utf8_str())) {
        case NUMBERED_LIST:
            m_abiProperties += "Numbered List";
            break;
            
        case LOWERCASE_LIST:
            m_abiProperties += "Lower Case List";
            break;
            
        case UPPERCASE_LIST:
            m_abiProperties += "Upper Case List";
            break;
            
        case LOWERROMAN_LIST:
            m_abiProperties += "Lower Roman List";
            break;
            
        case UPPERROMAN_LIST:
            m_abiProperties += "Upper Roman List";
            break;
            
        default:
            UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
    }
}


/**
 * Maps the value of the OpenDocument attribute style:num-format to the
 * correspondent AbiWord "type" attribute of the list (<l>) element tag.
 * 
 * @param pStyleNumFormat The value of the style:num-format attribute.
 */
void ODi_Numbered_ListLevelStyle::_setAbiListType(const XML_Char* pStyleNumFormat) {

    if (!pStyleNumFormat) {
        // Use an arbitrary list type.
        UT_UTF8String_sprintf(m_abiListType, "%d", NUMBERED_LIST);
        
    } else if (!UT_strcmp(pStyleNumFormat, "1")) {
        UT_UTF8String_sprintf(m_abiListType, "%d", NUMBERED_LIST);
        
    } else if (!UT_strcmp(pStyleNumFormat, "a")) {
        UT_UTF8String_sprintf(m_abiListType, "%d", LOWERCASE_LIST);
        
    } else if (!UT_strcmp(pStyleNumFormat, "A")) {
        UT_UTF8String_sprintf(m_abiListType, "%d", UPPERCASE_LIST);
        
    } else if (!UT_strcmp(pStyleNumFormat, "i")) {
        UT_UTF8String_sprintf(m_abiListType, "%d", LOWERROMAN_LIST);
        
    } else if (!UT_strcmp(pStyleNumFormat, "I")) {
        UT_UTF8String_sprintf(m_abiListType, "%d", UPPERROMAN_LIST);
        
    } else {
        // Use an arbitrary list type.
        UT_UTF8String_sprintf(m_abiListType, "%d", NUMBERED_LIST);
    }
}
