#ifndef _HTML_H
#define _HTML_H

/*

HTML classes for CGI programming in C++.

Author: Matthew W. Coan
Date: Sun May  5 15:40:54 EDT 2013

*/

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <map>

namespace html_tools {

using namespace std;

struct html_exception { };

class html {
public:
   typedef vector< string > string_vector_type;

private:
   string_vector_type page;

public:
   html() { }
   html(const html & ht) :page(ht.page) { }
   html(const string & filename);
   virtual ~html() { }

   html & operator=(const html & right) {
      page = right.page;
      return *this;
   } 

   string to_string() {
      string ret;
      for(size_t i = 0; i < page.size(); i++)
         ret += page[i] + "\n";
      return ret;
   }

   operator string() {
      return to_string();
   }

   ostream & write(ostream & out) {
      for(size_t i = 0; i < page.size(); i++)
         out << page[i] << endl;
      out << flush;
      return out;
   }

   bool read_line(istream & in, string & line) {
      bool ret = false;
      char ch;

      line = "";

      ch = in.get();

      while(ch != '\n' && in) {
         line += ch;

         ret = true;

         ch = in.get();
      }
      return ret;
   }

   istream & read(istream & in) {
      string line;
      page.clear();
      while(read_line(in, line)) {
         page.push_back(line); 
      }
      return in;
   }

   string expand(const string & line, const string & start_code, const string & end_code) {
      string ret;
      size_t i,j;
      bool found = false;
      for(i = 0; i < line.size(); i++) {
         found = false;
         for(j = 0; j < start_code.size(); j++) {
            if(line[i+j] != start_code[j]) {
               found = false;
               break;
            }
            else {
               found = true;
            }
         }
         if(found) {
            i += start_code.size();
            ret += end_code;
            i--;
         }
         else {
            ret += line[i];
         }
      } 
      return ret;
   }

   void expand(const string & start_code, const string & end_code) {
      for(size_t i = 0; i < page.size(); i++) {
         page[i] = expand(page[i], start_code, end_code);
      }
   }

   void expand(const string & start_code, const char value) {
      char buffer[100];
      sprintf(buffer, "%c", value);
      expand(start_code, buffer);
   }

   void expand(const string & start_code, const int value) {
      char buffer[100];
      sprintf(buffer, "%d", value);
      expand(start_code, buffer);
   }
   void expand(const string & start_code, const float value) {
      char buffer[100];
      sprintf(buffer, "%f", value);
      expand(start_code, buffer);
   }

   void expand(const string & start_code, const double & value) {
      char buffer[100];
      sprintf(buffer, "%f", value);
      expand(start_code, buffer);
   }

   void expand(const string & start_code, const long & value) {
      char buffer[100];
      sprintf(buffer, "%ld", value);
      expand(start_code, buffer);
   }

   html get_inner_html(const string & start_tag, const string & end_tag) {
      html temp;
      for(size_t i = 0; i < page.size(); i++) {
         if(page[i] == start_tag) {
            i++;
            if(i < page.size()) {
               while(page[i] != end_tag) {
                  temp.page.push_back(page[i]);
                  i++;
                  if(i >= page.size()) {
                     break;
                  }
               }
            }
            break;
         }
      }
      return temp;
   }

   void expand_inner_html(const string & start_tag, const string & end_tag, const string & temp) {
      html ret;
      for(size_t i = 0; i < page.size(); i++) {
         if(page[i] == start_tag) {
            while(page[i] != end_tag) {
               i++;
               if(i >= page.size()) {
                  break;
               }
            }
            ret.page.push_back(temp);
         }
         else {
            ret.page.push_back(page[i]);
         }
      }
      *this = ret;
   }
};


inline
ostream & 
operator<<(ostream & out, html_tools::html & page)
{
   page.write(out);
   return out;
}

inline
istream & 
operator>>(istream & in, html_tools::html & page)
{
   page.read(in);
   return in;
}

inline
html::html(const string & filename) 
{
   ifstream fin(filename.c_str(), ios::in);
   if(fin) {
      read(fin);
      fin.close();
   }
   else {
      throw html_exception();
   }
}

}

#endif /* _HTML_H */
