/* 

                          Firewall Builder

                 Copyright (C) 2000 Vadim Kurland

  Author:  Vadim Kurland     vadim@vk.crocodile.org

  $Id: FWObject.hh,v 1.21 2002/05/28 03:29:21 vkurland Exp $


  This program is free software which we release under the GNU General Public
  License. You may redistribute and/or modify this program under the terms
  of that 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.
 
  To get a copy of the GNU General Public License, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#ifndef  __FWOBJECT_HH_FLAG__
#define  __FWOBJECT_HH_FLAG__

#include <string>
#include <list>
#include <map>
#include <set>

#include <libxml/parser.h>
#include <libxml/tree.h>

#include <fstream>
#include <cstdlib>

#include <fwbuilder/FWException.hh>

namespace libfwbuilder
{

class FWObject;
class FWReference;
class FWObjectTypedChildIterator;

#define DECLARE_FWOBJECT_SUBTYPE(name) \
   static    const char *TYPENAME; \
   virtual   std::string getTypeName() const { return TYPENAME; } \
   static bool isA(const FWObject *o) { return o && o->getTypeName()==TYPENAME; }  \
   static name* cast(FWObject *o) { return dynamic_cast<name*>(o); } \
   static const name* constcast(const FWObject *o) { return dynamic_cast<const name*>(o); }

   
/**
 * This class represents base class for all
 * objects we are dealing with.
 *
 * FWObject can have children, that is other objects of the same class
 * or derived classes which are included in this one
 */
class FWObject : public std::list<FWObject*>
{

private:

    int            ref_counter;
    bool           dirty;
    FWObject      *parent;
    static std::string NOT_FOUND;

protected:

    std::string         xml_name;

    std::map<std::string, std::string> data;
    
    void      _adopt(FWObject *obj);   // increments reference
    
    /**
     * Finds direct child of this object with given name.
     */
    FWObject* _find(const std::string& name) const;

    /**
     * Finds all references to the object 'obj' in object
     * tree starting from 'this' and address them to resulting
     * set.
     */
    virtual void findAllReferences(const FWObject *obj, std::set<FWReference*> &res);
    
    FWObject();

    /**
     *  Parameter 'root' is a pointer at the root object of the tree,
     *  we are going to add this newly created object to.
     */
    FWObject(const FWObject *root);

public:

    DECLARE_FWOBJECT_SUBTYPE(FWObject);

    FWObject(const FWObject &copy);

    virtual void       fromXML    (xmlNodePtr xml_parent_node) throw(FWException);
    virtual xmlNodePtr toXML      (xmlNodePtr xml_parent_node) throw(FWException);
    xmlNodePtr toXML(xmlNodePtr xml_parent_node, bool process_children) throw(FWException);

    /**
     *  Rarely used feature: we can change the name of XML element
     *  represented by the class derived from FWObject if we want to. For
     *  example, used in all "Any"  objects so we did not have to create extra
     *  classes
     * 
     */
    void setXMLName (const std::string &);

    virtual  ~FWObject();

    int ref()   { ++ref_counter; return(ref_counter); }
    int unref() { --ref_counter; return(ref_counter); }

    /**
     * It is same as calling duplicate(x, FALSE);
     */
    virtual FWObject& operator=(const FWObject &) throw(FWException);

    /**
     * This method copies content of object 'x' in the object 'this'.
     * depending on 'preserve_id' flag, Id are either copied or new
     * ones are issued.
     */
    virtual FWObject& duplicate(const FWObject *obj, bool preserve_id = true) throw(FWException);
    
    void      Show();
    void      Hide();

    FWObject* getParent() const;
    void      setParent(FWObject *p);

    bool    exists(const std::string &name) const;

    void    remStr(const std::string &name);

    const std::string &getStr(const std::string& name) const;
    void    setStr(const std::string &name, const std::string &val);

    int     getInt(const std::string &name) const;
    void    setInt(const std::string &name, int    val);

    bool    getBool(const std::string &name) const;
    void    setBool(const std::string &name, bool val);
    void    setBool(const std::string &name, const std::string &val);

    const std::string &getName() const;
    void          setName(const std::string& n);
    
    const std::string &getComment() const;
    void          setComment(const std::string& c);

    const std::string &getLibrary() const;
    void          setLibrary(const std::string& c);

    const std::string  &getId() const;
    void           setId(const std::string& c);

            void addAt(const std::string& where_id, FWObject *obj);
    virtual void add(FWObject *obj,bool validate=true);
    virtual void insert_before(FWObject *o1,FWObject *obj);
    virtual void insert_after(FWObject *o1,FWObject *obj);

    /**
     * In direct children of 'this' swaps all references
     * to o1 with o2 and vice versa.
     */
    virtual void swapObjects(FWObject *o1,FWObject *o2);

    virtual bool GUISortOrder(const FWObject *a, const FWObject *b);
    virtual void sortChildren();
      
    /**
     * Finds first instance of 'obj' in children of this
     * object and removes if. If 'obj' reference counter
     * reaches 0 it is also deleted.
     */
    virtual void remove(FWObject *obj, bool delete_if_last=true);

    /**
     * Finds and removes instances of 'obj' recursively in the
     * whole tree under this object
     */
    virtual void removeAllInstances(FWObject *obj);

    /**
     * Adds reference object pointing to 'obj' as a child of 'this'
     */
    virtual void addRef(FWObject *obj);
    
    /**
     * Removes reference to given object among
     * children of 'this'.
     */
    virtual void removeRef(FWObject *obj);

    /**
     * Removes all references to 'obj' recursively in the whole tree
     * under 'this'
     */
    virtual void removeAllReferences(FWObject *obj);

    /**
     * Finds all references to the object 'obj' in object
     * tree starting from 'this'.
     */
    virtual std::set<FWReference*> findAllReferences(const FWObject *obj);

    /*
     *  Create appropriate reference object for itself.
     *  Different object require different class of reference. e.g.:
     *  for Host reference should be of class FWObjectReference
     *  for Service reference should be of class FWServiceReference
     */
    virtual FWReference* createRef();

    /*
     * verify whether given object type is approppriate as a child
     */
    virtual bool  validateChild(FWObject *o);

    /**
     * forcefully destroys all objects in the subtree under this,
     * except this. This method ignores reference counters and simply
     * deletes everything.
     */
    void destroyChildren();

    void clearChildren(bool recursive=true);
    
    int getChildrenCount();

    virtual void dump(bool recursive,bool brief,int offset=0);
    virtual void dump(std::ostream &f,bool recursive,bool brief,int offset=0);

    /**
     *   Returns root of the objects tree this object is part of
     */
    FWObject* getRoot() const;

    /**
     * Returns object with given ID. If recursive is 'false'
     * search is restricted to direct children of given object
     * and itslef. If it is true, method proceeds to all chidren of all
     * objects starting from current one.
     *
     * If dereference is 'false', references are treated as regular objects
     * (that is, ID of FWReference object itself is compared with id). If
     * dereference is 'true' then ID of the object pointed at by the reference
     * is compared with id
     */
    virtual FWObject* getById  (const std::string &id, 
				bool recursive=false, 
				bool dereference=false);

    /**
     * Returns list of direct children of current object
     * whose getTypeName() same as given.
     * If not found, empty list is returned.
     */
    virtual std::list<FWObject*> getByType(const std::string &type_name) const;

    /**
     * Returns list of direct children of current object
     * whose getTypeName() same as given.
     * If not found, end() is returned.
     */
    virtual FWObjectTypedChildIterator findByType(const std::string &type_name) const;

    /**
     * Returns first of direct children of current object
     * whose getTypeName() same as given or NULL if not found.
     */
    virtual FWObject* getFirstByType(const std::string &type_name) const;

    virtual void    setDirty(bool f,bool recursive=false);
    virtual bool    isDirty(bool recursive);

    // Attributes iterator
    std::map<std::string, std::string>::const_iterator dataBegin() { return data.begin(); }
    std::map<std::string, std::string>::const_iterator dataEnd  () { return data.end();   }

};

class FWObjectTypedChildIterator
{
    public:

    FWObjectTypedChildIterator(const FWObjectTypedChildIterator &o);
    
    FWObjectTypedChildIterator(const FWObject *o, const std::string &_type_name);
    
    bool operator==(const FWObject::const_iterator& __x) const;
    bool operator!=(const FWObject::const_iterator& __x) const;
    FWObject *operator*() const;
    FWObjectTypedChildIterator& operator++();
    FWObjectTypedChildIterator& operator--();
    
    const FWObject::const_iterator &begin() { return _begin; }
    const FWObject::const_iterator &  end() { return _end  ; }

    protected:
    
    std::string type_name;
    FWObject::const_iterator real_iterator;
    FWObject::const_iterator _begin;
    FWObject::const_iterator _end;
};
 
/**
 * Predicate class testing object pointers for name eqivalence.
 * name is obtained by calling getName() method.
 * This class could be used in STL Algoriths find_if, and others.
 */
class FWObjectNameEQPredicate: public std::unary_function<FWObject*, bool>
{
    std::string n;
    
    public:
    
    FWObjectNameEQPredicate(const std::string &name):n(name) {}
    
    bool operator()(const FWObject *o) const 
    {
        return o->getName()==n;
    }
};

/**
 * Predicate class testing object pointers for type name eqivalence.
 * name is obtained by calling getTypeName() method.
 * This class could be used in STL Algoriths find_if, and others.
 */
class FWObjectTypeNameEQPredicate: public std::unary_function<FWObject*, bool>
{
    std::string n;
    
    public:
    
    FWObjectTypeNameEQPredicate(const std::string &name):n(name) {}
    
    bool operator()(const FWObject *o) const 
    {
        return o->getTypeName()==n;
    }
};

}

#endif // _FWOBJECT_HH







