#include "baseserv.h"
#include <wx/filename.h>
#include <wx/tokenzr.h>
#include <wx/sstream.h>
#include <wx/zstream.h>

//////////////////////////////////////////////////////////////////////////////
// TFileToIndex: incapsula le info sui file da indicizzare
///////////////////////////////////////////////////////////////////////////////

class TFileToIndex
{
  protected:
    wxFileName _filename;
    wxStringTokenizer _contents;

    bool _dirty;

    static void ReadPDF(wxFileInputStream& file, wxString& output);
    static void ReadTXT(wxFileInputStream& file, wxString& output);

  public:
    TFileToIndex();
    TFileToIndex(const wxString& strFileName);

    const bool IsOk() const;
    const bool Dirty() const;

    void SetFileName(const wxString& strFileName);

    wxStringTokenizer& GetText();
};

TFileToIndex::TFileToIndex(): _dirty(true)
{
}

TFileToIndex::TFileToIndex(const wxString& strFileName): _filename(strFileName), _dirty(true)
{
}

void TFileToIndex::SetFileName(const wxString& strFileName)
{
  _dirty = true;
  _filename = strFileName;
}

const bool TFileToIndex::IsOk() const
{
  return _filename.IsOk();
}

const bool TFileToIndex::Dirty() const
{
  return _dirty;
}

void TFileToIndex::ReadTXT(wxFileInputStream& file, wxString& output)
{
  file.Read(wxStringBuffer(output,file.GetSize()),file.GetSize());
}

void TFileToIndex::ReadPDF(wxFileInputStream& file, wxString& output)
{
  wxString buffer;
  file.Read(wxStringBuffer(buffer,file.GetSize()),file.GetSize());

  bool morestreams = true;

	while (morestreams)
	{
		size_t streamstart = buffer.Index("stream");
		size_t streamend = buffer.Index("endstream");
		if (streamstart>0 && streamend>streamstart)
		{
			streamstart += 6;
      wxZlibInputStream inflated(wxStringInputStream(buffer.Mid(streamstart,streamend-streamstart)), wxZLIB_AUTO);
      inflated.Read(wxStringOutputStream(&output));
      output << " ";

			buffer = buffer.Mid(streamend+7);
		}
		else
		{
			morestreams = false;
		}
	}
}

wxStringTokenizer& TFileToIndex::GetText()
{
  if (Dirty())
  {
    _contents = wxStringTokenizer(" ", " ");

    if (IsOk())
    {
      wxFileInputStream stream(_filename.GetFullPath());

      if (stream.CanRead())
      {
        wxString strContents(" ");
        if (!_filename.GetExt().CmpNoCase("pdf"))
        {
          ReadPDF(stream, strContents);
        }
        if (!_filename.GetExt().CmpNoCase("txt") || !_filename.GetExt().CmpNoCase("ini") || !_filename.GetExt().CmpNoCase("log"))
        {
          ReadTXT(stream, strContents);
        }
        _contents = wxStringTokenizer(strContents, " \t\r\n.,:;(){}[]\"=", wxTOKEN_STRTOK);
      }
    }
  }

  return _contents;
}

//////////////////////////////////////////////////////////////////////////////
// TIndexingServer
///////////////////////////////////////////////////////////////////////////////

class TIndexingServer : public TBaseServerApp
{
protected:  
	virtual const wxChar* GetAppName() const;
  virtual void ProcessCommand(wxString cmd, wxSocketBase& outs);
  void ProcessHttpGet(wxString cmd, wxSocketBase& outs);
  void ProcessHttpPost(wxString cmd, wxSocketBase& outs);

protected:
	bool IsMagicName(wxString& strFilename) const;
  void GenerateFileFromGet(wxString& strFilename);
  void GenerateFileFromPost(wxString& strFilename, THashTable& thArgs);
};

const wxChar* TIndexingServer::GetAppName() const
{
	return "Indexing";
}

bool TIndexingServer::IsMagicName(wxString& strFilename) const
{
  wxString strName;
	wxSplitPath(strFilename, NULL, &strName, NULL);
  strName.MakeLower();
  const int q = strName.Find('?');
	if (q > 0)
	  strName.Truncate(q);

	if (strName == "index")
	{
		strFilename = strName;
		return true;
	}

	if (strName == "results")
	{
		strFilename = strName;
		return true;
	}

  return false;
}

void TIndexingServer::GenerateFileFromGet(wxString& strFilename)
{
  wxString strName, strArgs;
	wxSplitPath(strFilename, NULL, &strName, NULL);
  strName.MakeLower();
  const int q = strFilename.Find('?');
	if (q > 0)
		strArgs = strFilename.Mid(q+1);

	if (strName == "index")
	{
		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html).AddChild("center").AddChild("form");
    body.SetAttr("action", "results.htm");
    body.SetAttr("method", "POST");

		body.AddChild("h1") << "Welcome to the indexing test server";
		body.AddChild("br");
    
		TXmlItem& table = body.AddChild("table");
    TXmlItem& textfield = table.AddChild("tr").AddChild("td").AddChild("input");
    TXmlItem& button = table.AddChild("tr").AddChild("td").AddChild("input");
    button.SetAttr("value", "Search");
    button.SetAttr("type", "submit");
    textfield.SetAttr("type", "text");
    textfield.SetAttr("name", "filetodisplay");

		strFilename = GetTempFilename();
		html.Save(strFilename);
	}
}

void TIndexingServer::GenerateFileFromPost(wxString& strFilename, THashTable& htArgs)
{
  wxString strName, strArgs;
	wxSplitPath(strFilename, NULL, &strName, NULL);
  strName.MakeLower();
  const int q = strFilename.Find('?');
	if (q > 0)
		strArgs = strFilename.Mid(q+1);

	if (strName == "results")
	{
    TFileToIndex file(htArgs.Get("filetodisplay"));
    wxStringTokenizer& text = file.GetText();

		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html).AddChild("center");

		body.AddChild("h1") << "Text contained in file";
		body.AddChild("br");

    TXmlItem& results = body.AddChild("div");

    while (text.HasMoreTokens())
    {
       results << text.GetNextToken() << ", ";
    }

		strFilename = GetTempFilename();
		html.Save(strFilename);
  }
}

void TIndexingServer::ProcessHttpGet(wxString cmd, wxSocketBase& outs)
{
  const int stop = cmd.Find(" HTTP");
	wxString str = cmd.Mid(4, stop-4).Trim();

	if (str == "/")
		str += "index.htm";
	wxString strFilename = GetDocumentRoot() + str;

	if (IsMagicName(strFilename))
		GenerateFileFromGet(strFilename);
	SendFile(strFilename, outs);
}

void TIndexingServer::ProcessHttpPost(wxString cmd, wxSocketBase& outs)
{
  const int stop = cmd.Find(" HTTP");
	wxString str = cmd.Mid(5, stop-5).Trim();

  wxString args;

	const int pos = cmd.Find("\r\n\r\n");
	if (pos > 0)
	  args = cmd.Mid(pos+4);

	THashTable hashArgs(17);
  ParseArguments(args, hashArgs);

	if (str == "/")
		str += "results.htm";
	wxString strFilename = GetDocumentRoot() + str;

  if (IsMagicName(strFilename))
		GenerateFileFromPost(strFilename, hashArgs);
	SendFile(strFilename, outs);
}

void TIndexingServer::ProcessCommand(wxString cmd, wxSocketBase& outs)
{
  if (cmd.StartsWith("GET "))
		ProcessHttpGet(cmd, outs); else
  if (cmd.StartsWith("POST "))
		ProcessHttpPost(cmd, outs);
}

IMPLEMENT_APP(TIndexingServer)