/*
 * @(#)Server.h
 *
 * This file is part of webCDwriter - Network CD Writing.
 *
 * Copyright (C) 1999-2003 Jörg P. M. Haeger
 *
 * webCDwriter is free software. See CDWserver.cpp for details.
 */

#ifndef SERVER_H
#define SERVER_H

#include <time.h>
#include "CDstate.h"
#include "Options.h"
#include "Session.h"

enum writerStates { idle, reserved, blanking,
	mkisofs, writing, fixating, verifying, reading };

struct Writer {
	int fifoPercent;
	class Server *owner;
	enum writerStates state;
	int percent, reservedUntil;

	Writer() {
		fifoPercent = 100;
		owner = NULL;
		state = idle;
		percent = 0;
		reservedUntil = 0;
	}
};

/*
 * Implementation of a server process.
 *
 * @version 20030806
 * @author Jörg P. M. Haeger
 */
class Server {
	public: static const char
		errorInCommand[], hint[], hintPercentDone[], info[], unknown[];

	private: static pthread_mutex_t activateConfigMutex;
	private: static bool activateConfigPending;
	private: static int activeServersNum;
	protected: static String features, license, serialNo, validity;
	protected: static int maxServers, maxUsers;
	static pthread_mutex_t licenseMutex;
	static int nextServerNo;
	static class WriterQueues *writerQueue;
	static Writer *writers;

	int serverNo, readerNo, writerNo;
	time_t connectionT0, sessionT0, sessionT1, burnT0;
	int sock;
	FILE *inStream;
	char errorStr[1024], lineStr[1024];
	int logFilesNum;

	// states
	int bytesReceived;
	int openCommands, isOffline, lineStrPending;
	String
		clientIP;
	const char
		*clientSystemName, *clientSystemVersion,
		*clientUserID, *clientUserName,
		*userID, *userPassword;
	bool ejectBeforeVerify;

	// modes
	int
		modeShowCdrecord, modeShowMkisofs;

	struct Options options;
	struct CDstate CDstate;
	class Session *session;
	const char *tmpSessionID;
	FILE *project;

	int quit;

public:
	Server(int socket);
	virtual ~Server();
	static void activateConfig();
	static int getActiveServersNum() { return activeServersNum; }
	const char *getClientIP() { return clientIP.getBytes(); }
	const char *getClientUserName() { return clientUserName; }
	int getNo() { return serverNo; }
	static int getWriterFifoPercent(int writerNo)
		{ return writers[writerNo].fifoPercent; }
	static Server *getWriterOwner(int writerNo)
		{ return writers[writerNo].owner; }
	static int getWriterPercent(int writerNo)
		{ return writers[writerNo].percent; }
	static int getWriterReservedUntil(int writerNo)
		{ return writers[writerNo].reservedUntil; }
	static enum writerStates getWriterStatus(int writerNo)
		{ return writers[writerNo].state; }
	static int hextoint(const char *str, int length);
	static void initStatic();
	void run();
	static void terminate();
	int waitForService(class Queue *queue, int toRank);
	int waitForService(class Queue *queue, int toRank, int ID);

private:
	void addArgs(Process &p, const char *args);
	protected: virtual String *addKey(String &preparerID) {
		return new String(preparerID);
	}
	void blank(char *cmdStr);
	void burnCopy();
	void burnSession();
	protected: virtual void checkDVDSize() {}
	void checkFileName(const char *fileName);
	void checkLoggedIn();
	protected: virtual void checkMediumSupport(const char *medium) {
		throw new Exception(S.e
			+ "This version of CDWserver has no " + medium + " support!");
	}
	void checkOpenSession();
	static String *dateToShortString();
	void eject();
	void ejectReader();
	void errorToClient(const char *format, ...);
	void errorToClient(String &str);
	void executeCmd();
	int filterCancel(int cancel);

	public: static String *getFeatures() {
		pthread_mutex_lock(&licenseMutex);
		String *str = new String(features);
		pthread_mutex_unlock(&licenseMutex);
		return str;
	}

	public: static String *getLicense() {
		pthread_mutex_lock(&licenseMutex);
		String *str = new String(license);
		pthread_mutex_unlock(&licenseMutex);
		return str;
	}

	public: static int getMaxServers() { return maxServers; }
	public: static int getMaxUsers() { return maxUsers; }

	public: static String *getSerialNo() {
		pthread_mutex_lock(&licenseMutex);
		String *str = new String(serialNo);
		pthread_mutex_unlock(&licenseMutex);
		return str;
	}

	public: static String *getValidity() {
		pthread_mutex_lock(&licenseMutex);
		String *str = new String(validity);
		pthread_mutex_unlock(&licenseMutex);
		return str;
	}

	protected: const char *getNewLogFileName(char *str);
	protected: virtual bool isMediumOK();
	void load();
	void logCDstate(const char *resultStr);
	void logConnection();
	void logSession(const char *typeStr, const char *resultStr);
	void nextCmd();
	int noDisc(int trayOpenIfNoDisc = 0);

	protected: virtual void putFileContinue(
			FILE *inStream, int length) {
		session->putFileContinue(inStream, length);
		successToClient("file continued");
	}

	protected: virtual void putFileEnd(int mode, int time) {
		session->putFileEnd(mode, time);
	}

	protected: virtual void putFileStart(
			const char *arg1, const char *arg2) {
		session->putFileStart(arg1);
	}

	void readATIP();
	void readMultiSessionInfo();
	protected: virtual void readTOC();
	char *removeEscChars(char *str);
	void reserveDevice(int ID);
	void resetImageFile();
	static void resetStatic();
	void run_cdrdaoCopy();
	void run_cdrecord();
	void run_cdrecord2();
	protected: virtual void run_cdrecordBlank(const char *modeStr);
	void run_cdrecordCopy();
	protected: virtual void run_growisofs() { }
	void run_mkisofs();
	void saveLineStr();
	protected: virtual void showFeatures();
	void showWaitForDiscMsg();
	static const char *spaceToEsc(const char *str);
	protected: void start();
	void start_mkisofs(Process &p);
	void successToClient(const char *format, ...);
	static char *timeToDigits(time_t t, char *str, size_t size);
	static String *timeToShortString();
	static String *timeToString(time_t t = 0);
	void toClient(const char *type, const char *format, ...);
	void toClient(const char *type, String &str);
	void verify();
	int waitForDisc();
	void writeImageToRawDevice();
};

#endif
