// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * TODO: insert short description here
 *//*
 * Authors: see git history
 *
 * Copyright (C) 2018 Authors
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */
/*
 * attribute-rel-css.cpp
 *
 *  Created on: Jul 25, 2011
 *      Author: abhishek
 */

/** \class SPAttributeRelCSS
 *
 * SPAttributeRelCSS class stores the mapping of element->style_properties
 * relationship and provides a static function to access that
 * mapping indirectly(only reading).
 */

#include <fstream>
#include <sstream>
#include <iostream>

#include "attribute-rel-css.h"

#include "path-prefix.h"
#include "preferences.h"

SPAttributeRelCSS * SPAttributeRelCSS::instance = nullptr;
bool SPAttributeRelCSS::foundFileProp = false;
bool SPAttributeRelCSS::foundFileDefault = false;

/*
 * This function checks whether an element -> CSS property pair 
 * is allowed or not
 */
bool SPAttributeRelCSS::findIfValid(Glib::ustring property, Glib::ustring element)
{
    if (SPAttributeRelCSS::instance == nullptr) {
        SPAttributeRelCSS::instance = new SPAttributeRelCSS();
    }
    
    // Always valid if data file not found!
    if( !foundFileProp ) return true;

    // Strip of "svg:" from the element's name
    Glib::ustring temp = element;
    if ( temp.find("svg:") != std::string::npos ) {
        temp.erase( temp.find("svg:"), 4 );
    }

    // Don't check for properties with -, role, aria etc. to allow for more accessibility
    // FixMe: Name space list should be created when file read in.
    if (property[0] == '-'
        || property.substr(0,4) == "role"
        || property.substr(0,4) == "aria"
        || property.substr(0,5) == "xmlns"
        || property.substr(0,8) == "inkscape:"
        || property.substr(0,9) == "sodipodi:"
        || property.substr(0,4) == "rdf:"
        || property.substr(0,3) == "cc:"
        || property.substr(0,4) == "ns1:"  // JessyInk
        || property.substr(0,4) == "osb:"  // Open Swatch Book
        || (SPAttributeRelCSS::instance->propertiesOfElements[temp].find(property)
            != SPAttributeRelCSS::instance->propertiesOfElements[temp].end()) ) {
        return true;
    } else {
        //g_warning( "Invalid attribute: %s used on <%s>", property.c_str(), element.c_str() );
        return false;
    }
}

/*
 * This function checks whether an CSS property -> default value 
 * pair is allowed or not
 */
bool SPAttributeRelCSS::findIfDefault(Glib::ustring property, Glib::ustring value)
{
    if (SPAttributeRelCSS::instance == nullptr) {
        SPAttributeRelCSS::instance = new SPAttributeRelCSS();
    }

    // Always false if data file not found!
    if( !foundFileDefault ) return false;

    if( instance->defaultValuesOfProps[property] == value) {
        return true;
    } else {
        return false;
    }
}

/*
 * Check if property can be inherited.
 */
bool SPAttributeRelCSS::findIfInherit(Glib::ustring property)
{
    if (SPAttributeRelCSS::instance == nullptr) {
        SPAttributeRelCSS::instance = new SPAttributeRelCSS();
    }

    // Always false if data file not found!
    if( !foundFileDefault ) return false;

    return instance->inheritProps[property];
}

/*
 * Check if attribute is a property.
 */
bool SPAttributeRelCSS::findIfProperty(Glib::ustring property)
{
    if (SPAttributeRelCSS::instance == nullptr) {
        SPAttributeRelCSS::instance = new SPAttributeRelCSS();
    }

    // Always true if data file not found!
    if( !foundFileProp ) return true;

    return ( instance->defaultValuesOfProps.find( property )
             != instance->defaultValuesOfProps.end() );
}

SPAttributeRelCSS::SPAttributeRelCSS()
{
    // Read data from standard path
    std::string filepath = INKSCAPE_ATTRRELDIR;
    filepath += "/cssprops";

    // Try and load data from filepath
    if (readDataFromFileIn(filepath, SPAttributeRelCSS::prop_element_pair)) {
        foundFileProp = true;
    }
    
    // Read data from standard path
    filepath = INKSCAPE_ATTRRELDIR;
    filepath += "/css_defaults";
    
    // Try and load data from filepath
    if (readDataFromFileIn(filepath, SPAttributeRelCSS::prop_defValue_pair)) {
        foundFileDefault = true;
    }

}

bool SPAttributeRelCSS::readDataFromFileIn(Glib::ustring fileName, storageType type)
{
    std::fstream file;
    file.open(fileName.c_str(), std::ios::in);
    
    if (!file.is_open()) {
        // Display warning for file not open
        g_warning("Could not open the data file for CSS attribute-element map construction: %s", fileName.c_str());
        file.close();
        return false;
    }

    while (!file.eof()) {
        std::stringstream ss;
        std::string s;

        std::getline(file,s,'"');
        std::getline(file,s,'"');
        if (s.size() > 0 && s[0] != '\n') {
            std::string prop = s;
            getline(file,s);
            ss << s;
            
            // Load data to structure that holds element -> set of CSS props
            if (type == SPAttributeRelCSS::prop_element_pair) {
                while (std::getline(ss,s,'"')) {
                    std::string element;
                    std::getline(ss,s,'"');
                    element = s;                               
                    propertiesOfElements[element].insert(prop);
                }
            // Load data to structure that holds CSS prop -> default value    
            } else if (type == SPAttributeRelCSS::prop_defValue_pair) {
                std::string value;
                std::getline(ss,s,'"');
                std::getline(ss,s,'"');
                value = s;
                defaultValuesOfProps[prop] = value;
                std::getline(ss,s,'"');
                std::getline(ss,s,'"');
                gboolean inherit = false;
                if ( s.find( "yes" ) != std::string::npos ) {
                    inherit = true;
                }
                inheritProps[prop] = inherit;
            }
        }
    }
    
    file.close();
    return true;
}

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
