/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CMailMessageBody.cpp  -  description
                             -------------------
    begin                : 25 Oct 2004
    copyright            : (C) 2000-2006 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library 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 Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#include <sptk3/CMailMessageBody.h>
#include <sptk3/CStrings.h>
#include <sptk3/istring.h>
#include <sptk3/string_ext.h>

#include <vector>
#include <map>

using namespace std;
using namespace sptk;

/// A map of the HTML tags to remove or process
class CHtmlTagsToProcess : public map<istring,int> {
public:
   CHtmlTagsToProcess();
};

static CHtmlTagsToProcess tagsToProcess;

#define REMOVE_THIS_TAG 1
#define PROCESS_THIS_TAG 2

CHtmlTagsToProcess::CHtmlTagsToProcess() {
   insert(CHtmlTagsToProcess::value_type("HTML",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("BODY",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("BASE",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("CENTER",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("HEAD",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("TABLE",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("TBODY",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("TH",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("TR",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("TD",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("DIV",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("SPACER",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("SPAN",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("P",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("BR",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("SCRIPT",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("NOSCRIPT",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("NOBR",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("FONT",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("FORM",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("INPUT",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("H4",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("H3",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("H2",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("H1",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("STRONG",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("B",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("A",PROCESS_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("IMG",PROCESS_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("FRAME",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("IFRAME",REMOVE_THIS_TAG));
   insert(CHtmlTagsToProcess::value_type("FRAMESET",REMOVE_THIS_TAG));
}

string CMailMessageBody::processTag(string tag,string params) {
   if (lowerCase(tag) == "a") {
      int pos = lowerCase(params).find("src=");
      if (pos < 0) return "";
      char *p = (char*) params.c_str() + pos + 4;
      char *e = strpbrk(p," >/");
      if (e) *e = 0;
      return e;
   }
   return "";
}

string CMailMessageBody::stripHtml(const string& origHtml) {
   vector<string> html;
   unsigned    i = 0;

   split(html,origHtml,"<");

   // Remove comments and scripts
   const char *tagEnd = 0L;
   for (i = 0; i < html.size(); i++) {
      string& tag = html[i];
      if (tagEnd) {
         if (lowerCase(tag).find(tagEnd) != string::npos)
            tagEnd = 0;
         html.erase(html.begin()+i);
         i--;
         continue;
      }
      string tagLowerCase(lowerCase(tag));
      if (tagLowerCase.find("script") == 0) {
         tagEnd = "/script>";
         html.erase(html.begin()+i);
         i--;
         continue;
      }
      if (tagLowerCase.find("style") == 0) {
         tagEnd = "/style>";
         html.erase(html.begin()+i);
         i--;
      }
      if (tagLowerCase.find("!--") == 0) {
         tagEnd = "-->";
         html.erase(html.begin()+i);
         i--;
      }
      if (tagLowerCase.find("head") == 0) {
         tagEnd = "head>";
         html.erase(html.begin()+i);
         i--;
      }
   }

   for (i = 0; i < html.size(); i++) {
      char *start = (char *) html[i].c_str();
      char *end = strpbrk(start," >");
      char *params = NULL;
      if (!end) {
         html.erase(html.begin()+i);
         i--;
         continue;
      }
      if (*end == ' ') 
         params = end + 1;
      *end = 0;
      if (*start == '/') start++;
      CHtmlTagsToProcess::iterator it = tagsToProcess.find(start);
      if (params) 
         end = strchr(end + 1,'>');
      if (!end) {
         html.erase(html.begin()+i);
         i--;
         continue;
      }
      if (it != tagsToProcess.end()) {
         string text;
         if (it->second == REMOVE_THIS_TAG || !params)
            text = end + 1;
         else {
            text = processTag(start,params) + string(end + 1);
         }
         html[i] = replaceAll(replaceAll(replaceAll(trim(text),"&nbsp;"," "),"     "," "),"   "," ");
      }
      if (i && trim(html[i]).length() == 0) {
         html.erase(html.begin()+i);
         i--;
      }
   }

   string result;
   join(result,html," ");
   return result;
}

void CMailMessageBody::text(const string& messageText,bool smtp) {
   string msg;
   if (smtp)
      msg = replaceAll(messageText,"\n.\n","\n \n");
   else
      msg = messageText;
   if (upperCase(messageText.substr(0,100)).find("<HTML>") == string::npos) {
      m_type = MMT_PLAIN_TEXT_MESSAGE;
      m_plainText = msg;
      m_htmlText = "";
   } else {
      m_type = MMT_HTML_MESSAGE;
      m_plainText = stripHtml(msg);
      m_htmlText = msg;
   }
}
