/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */



#ifndef INK_XML_H
#define INK_XML_H

#include "List.h"

/*-------------------------------------------------------------------------
  InkXml.h

  This file defines the interface for parsing XML-style config files.  Such
  a file contains various XML objects, each with tags (or attibutes).  The
  parser's job is to build a database of these objects that can then be
  queried later to extract the desired information.
  -------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------
  InkXmlAttr
  -------------------------------------------------------------------------*/

class InkXmlAttr
{
public:
  InkXmlAttr(char *tag, char *value);
   ~InkXmlAttr();

  char *tag()
  {
    return m_tag;
  }
  char *value()
  {
    return m_value;
  }
  void display(FILE * fd = stdout);

private:
  char *m_tag;
  char *m_value;

public:
  LINK(InkXmlAttr, link);

private:
  // -- member functions that are not allowed --
  InkXmlAttr();
  InkXmlAttr(const InkXmlAttr &);
  InkXmlAttr & operator=(InkXmlAttr &);
};

/*-------------------------------------------------------------------------
  InkXmlObject

  An XmlObject has a name and a set of <tag,value> attributes.
  -------------------------------------------------------------------------*/

class InkXmlObject
{
public:
  InkXmlObject(char *object_name, bool dup_attrs_allowed = true);
   ~InkXmlObject();

  void clear_tags();
  int add_tag(char *tag, char *value);
  int add_attr(InkXmlAttr * attr);
  char *tag_value(char *tag_name);
  void display(FILE * fd = stdout);

  char *object_name()
  {
    return m_object_name;
  }
  InkXmlAttr *first()
  {
    return m_tags.head;
  }
  InkXmlAttr *next(InkXmlAttr * here)
  {
    return (here->link).next;
  }

private:
  char *m_object_name;
  bool m_dup_attrs_allowed;
  Queue<InkXmlAttr> m_tags;

public:
  LINK(InkXmlObject, link);

private:
  InkXmlObject * get_next_xml_object(int fd);

private:
  // -- member functions that are not allowed --
  InkXmlObject();
  InkXmlObject(const InkXmlObject &);
  InkXmlObject & operator=(InkXmlObject &);
};

/*-------------------------------------------------------------------------
  InkXmlConfigFile

  This object is used to parse an XML-style config file and create a
  database of resulting XML objects.
  -------------------------------------------------------------------------*/

class InkXmlConfigFile
{

public:
  InkXmlConfigFile(char *config_file);
   ~InkXmlConfigFile();

  void clear_objects();
  /*                                                                     */
  int parse(int fd);
  /*                                                                     */
  int parse();
  void add_object(InkXmlObject * object);
  InkXmlObject *find_object(char *object_name);
  void display(FILE * fd = stdout);

  InkXmlObject *first()
  {
    return m_objects.head;
  }
  InkXmlObject *next(InkXmlObject * here)
  {
    return (here->link).next;
  }

private:
  InkXmlObject * get_next_xml_object(int fd);
  InkXmlObject *parse_error();
  InkXmlObject *scan_object(int fd, char token);
  InkXmlAttr *scan_attr(int fd, char *ident);
  char next_token(int fd, bool eat_whitespace = true);
  char scan_comment(int fd);

private:
  char *m_config_file;
  unsigned m_line;
  unsigned m_col;
  Queue<InkXmlObject> m_objects;

private:
  // -- member functions that are not allowed --
  InkXmlConfigFile();
  InkXmlConfigFile(const InkXmlConfigFile &);
  InkXmlConfigFile & operator=(InkXmlConfigFile &);
};

class NameList
{
private:
  struct ListElem
  {
    char *m_name;
    LINK(ListElem, link);

    ListElem(char *name):m_name(name)
    {
    }
  };

public:
NameList():m_count(0) {
  }
  ~NameList() {
    clear();
  }

  void enqueue(char *name)
  {
    ListElem *e = NEW(new ListElem(name));
    m_list.enqueue(e);
    m_count++;
  }
  char *dequeue()
  {
    char *ret = NULL;
    ListElem *e = m_list.dequeue();
    if (e) {
      ret = e->m_name;
      delete e;
      m_count--;
    }
    return ret;
  }
  void clear()
  {
    ListElem *e;
    while ((e = m_list.dequeue()) != NULL) {
      delete e;
    }
    m_count = 0;
  }
  unsigned count()
  {
    return m_count;
  }

private:
  Queue<ListElem> m_list;
  unsigned m_count;
};

#endif /* INK_XML_H */
