//
// Server.cpp
//
// $Id: //poco/Main/WebWidgets/ExtJS/samples/Server/src/Server.cpp#4 $
//
// This sample demonstrates the XYZ class.
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//



#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionException.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/WebWidgets/RequestHandler.h"
#include "Poco/WebWidgets/WebApplication.h"
#include "Poco/WebWidgets/ExtJS/Utility.h"
#include "Poco/WebWidgets/Table.h"
#include "Poco/WebWidgets/SubmitButton.h"
#include "Poco/WebWidgets/CheckButton.h"
#include "Poco/WebWidgets/CheckButtonCell.h"
#include "Poco/WebWidgets/SimpleTableModel.h"
#include "Poco/WebWidgets/Form.h"
#include "Poco/WebWidgets/DataRetriever.h"
#include "Poco/WebWidgets/TextField.h"
#include "Poco/WebWidgets/TextFieldCell.h"
#include "Poco/File.h"
#include "Poco/Path.h"
#include "Poco/SharedPtr.h"
#include <iostream>


using Poco::Util::Application;
using Poco::Util::ServerApplication;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::OptionCallback;
using Poco::Util::HelpFormatter;
using Poco::Net::HTTPRequestHandlerFactory;
using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPServerRequest;
using Poco::Net::ServerSocket;
using Poco::Net::HTTPServer;
using Poco::Net::HTTPServerParams;
using Poco::SharedPtr;

using namespace Poco::WebWidgets;


class WebAppHandlerFactory: public HTTPRequestHandlerFactory
{
public:
	WebAppHandlerFactory(SharedPtr<WebApplication> pApp, const Poco::Path& dataPath, Poco::Logger* pLogger):
		_pApp(pApp),
		_dataRoot(dataPath),
		_aliases(),
		_pLogger(pLogger)
	{
		_aliases.insert(std::make_pair("", _dataRoot));
	}

	HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
	{
		const std::string& uri = request.getURI();
		Poco::URI url(uri);
		const std::string& path = url.getPath();
		const std::string& appPath = _pApp->getURI().getPath();
		if (path == appPath || 
			(path.size() > appPath.size() && path.find(appPath) == 0 && path[appPath.size()] == ';')
			)
			return new RequestHandler(_pApp);
		return new DataRetriever(_aliases, _pLogger);
	}
private:
	SharedPtr<WebApplication> _pApp;
	Poco::Path      _dataRoot;
	DataRetriever::Aliases   _aliases;
	Poco::Logger*   _pLogger;
};


class WebServer: public ServerApplication
{
public:
	WebServer(): _helpRequested(false)
	{
	}
	
	~WebServer()
	{
	}

protected:
	void initialize(Application& self)
	{
		loadConfiguration(); // load default configuration files, if present
		ServerApplication::initialize(self);
		logger().information("starting up");
	}
		
	void uninitialize()
	{
		logger().information("shutting down");
		ServerApplication::uninitialize();
	}

	void defineOptions(OptionSet& options)
	{
		ServerApplication::defineOptions(options);
		
		options.addOption(
			Option("help", "h", "display help information on command line arguments")
				.required(false)
				.repeatable(false)
				.callback(OptionCallback<WebServer>(this, &WebServer::handleHelp)));
	}

	void handleHelp(const std::string& name, const std::string& value)
	{
		_helpRequested = true;
		displayHelp();
		stopOptionsProcessing();
	}

	void displayHelp()
	{
		HelpFormatter helpFormatter(options());
		helpFormatter.setCommand(commandName());
		helpFormatter.setUsage("OPTIONS");
		helpFormatter.setHeader("A sample server application that demonstrates some of the features of the Util::ServerApplication class.");
		helpFormatter.format(std::cout);
	}

	int main(const std::vector<std::string>& args)
	{
		if (!_helpRequested)
		{
			ResourceManager::Ptr pRM = new ResourceManager();
			ExtJS::Utility::initialize(pRM, Poco::Path());
			SharedPtr<WebApplication> pWebApp = new WebApplication(Poco::URI("/"), pRM);
			LookAndFeel::Ptr laf(new LookAndFeel());
			Poco::WebWidgets::ExtJS::Utility::initialize(laf);
			pWebApp->setLookAndFeel(laf);
			Page::Ptr ptr = new Page("test");
			Form::Ptr pForm = new Form("form1", Poco::URI("/"));
			//pForm->setURL(...);
			Table::TableColumns tc;
			tc.push_back(new TableColumn(new TextFieldCell(0), "StaticText", 200,true ));
			tc.push_back(new TableColumn(new CheckButtonCell(0, "lbl", true), "CheckButton", 100, true));
			Table::Ptr pTable = new Table(tc, new SimpleTableModel(2));
			///init simpletablemodel
			pTable->setValue(std::string("one"), 0,0);
			pTable->setValue(std::string("two"), 1,0);
			pTable->setValue(std::string("three"), 2,0);
			pTable->setValue(std::string("four"), 3,0);
			pTable->setValue(std::string("five"), 4,0);
			pTable->setValue(std::string("12' 23''"), 5,0);

			pTable->setValue(true, 0,1);
			pTable->setValue(false, 1,1);
			pTable->setValue(true, 2,1);
			pTable->setValue(false, 3,1);
			pTable->setValue(true, 4,1);
			pTable->setValue(true, 5,1);
			pTable->setWidth(310);
			pTable->setHeight(200);
			pTable->setPaging(2);
			
			pForm->add(new TextField("txtfield"));
			CheckButton::Ptr ptrCheck2(new CheckButton("checkbutton", "CheckButton", false));
			pForm->add(ptrCheck2);
			SubmitButton::Ptr ptrBut(new SubmitButton("Submit"));
			ptrBut->setText("Submit");
			
			pForm->add(ptrBut);
			
			ptr->add(pForm);
			ptr->add(pTable);
			pWebApp->setCurrentPage(ptr);
	
			unsigned short port = (unsigned short) config().getInt("WebServer.port", 9980);
			std::string data = config().getString("WebServer.dataRoot", ".");
			Poco::Path aPath(data);
			aPath.makeAbsolute();
			aPath.makeDirectory();
			Poco::File aFile(aPath);
			if (!aFile.exists() || aFile.isFile())
				throw Poco::Util::InvalidArgumentException("dataRoot is either a file or doesn't exist: must be directory!");

			ServerSocket svs(port);
			HTTPServer srv(new WebAppHandlerFactory(pWebApp, aPath, &logger()), svs, new HTTPServerParams);
			srv.start();
			waitForTerminationRequest();
			srv.stop();
		}
		return Application::EXIT_OK;
	}
	
private:
	bool _helpRequested;
};


POCO_SERVER_MAIN(WebServer)
