#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include "devicesetup.h"
#include "mediad.h"

char *device::st_mountScript = NULL;
unsigned int device::_st_instances = 0;

device::device()
	: _hasVolume(false), _unLock(false), _name(NULL), _mountPoint(NULL), _curDevice(NULL), _curUDI(NULL), _curMediaType(unknown), _redirectedVideoDir(false), _mountPath(NULL), _mounted(false), _information(NULL)
{ 
	if((! device::st_mountScript) && (device::_st_instances == 0))
		device::st_mountScript = strdup("pmount.sh");
	device::_st_instances++;
}

device::device(const char* name, const char* deviceName, char* mountPoint, bool unLock) 
	: _hasVolume(false), _unLock(unLock), _name(NULL), _mountPoint(NULL), _curDevice(NULL), _curUDI(NULL), _curMediaType(unknown), _redirectedVideoDir(false), _mountPath(NULL), _mounted(false), _information(NULL)
{ 
	if((! device::st_mountScript) && (device::_st_instances == 0))
		device::st_mountScript = strdup("pmount.sh");
	device::_st_instances++;

	setDevice(deviceName);
	if(mountPoint) {
		if(_mountPoint) free(_mountPoint);
		_mountPoint = strdup(mountPoint); 
	}
	if(name)
		_name = strdup(name);
	else
		_name = NULL;
}

device::device(const device& dev) 
{ 
	if((! device::st_mountScript) && (device::_st_instances == 0))
		device::st_mountScript = strdup("pmount.sh");
	device::_st_instances++;
	if(dev._name)
		_name = strdup(dev._name); 
	else
		_name = NULL;
	if(dev._deviceName)
		strcpy(_deviceName, dev._deviceName); 
	else
		_deviceName[0] = '\0';
	if(dev._physicalDeviceName)
		strcpy(_physicalDeviceName, dev._physicalDeviceName); 
	else
		_physicalDeviceName[0] = '\0';
	if(dev._mountPoint)
		_mountPoint = strdup(dev._mountPoint); 
	else 
		_mountPoint = NULL;
	if(dev._curDevice)
		_curDevice = strdup(dev._curDevice); 
	else
		_curDevice = NULL;
	if(dev._curUDI)
		_curUDI = strdup(dev._curUDI); 
	else
		_curUDI = NULL;
	if(dev._mountPath)
		_mountPath = strdup(dev._mountPath); 
	else
		_mountPath = NULL;
	if(dev._information)
		_information = strdup(dev._information); 
	else
		_information = NULL;
	_curMediaType = dev._curMediaType;
	_unLock = dev._unLock; 
	_hasVolume = dev._hasVolume;
	_redirectedVideoDir = dev._redirectedVideoDir;
}

device& device::operator=(device const& dev) 
{ 
	if(dev._name)
		_name = strdup(dev._name); 
	else
		_name = NULL;
	if(dev._deviceName)
		strcpy(_deviceName, dev._deviceName); 
	else
		_deviceName[0] = '\0';
	if(dev._physicalDeviceName)
		strcpy(_physicalDeviceName, dev._physicalDeviceName); 
	else
		_physicalDeviceName[0] = '\0';
	if(dev._mountPoint)
		_mountPoint = strdup(dev._mountPoint); 
	else
		_mountPoint = NULL;
	if(dev._curDevice)
		_curDevice = strdup(dev._curDevice); 
	else
		_curDevice = NULL;
	if(dev._curUDI)
		_curUDI = strdup(dev._curUDI); 
	else
		_curUDI = NULL;
	if(dev._mountPath)
		_mountPath = strdup(dev._mountPath); 
	else
		_mountPath = NULL;
	if(dev._information)
		_information = strdup(dev._information); 
	else
		_information = NULL;
	_curMediaType = dev._curMediaType;
	_unLock = dev._unLock; 
	_hasVolume = dev._hasVolume;
	_redirectedVideoDir = dev._redirectedVideoDir;
	return *this; 
}

device::~device() 
{ 
	if(_mountPoint) 
		free(_mountPoint); 
	if(_curDevice) 
		free(_curDevice); 
	if(_curUDI) 
		free(_curUDI); 
	if(_name) 
		free(_name); 
	if(_mountPath) 
		free(_mountPath); 
	if(_information) 
		free(_information); 
	device::_st_instances--;
	if(device::_st_instances == 0)
		free(device::st_mountScript);
}

bool device::operator==(const char *deviceUDI) { 
	bool bRet = false;
	char *deviceURL= NULL;
	asprintf(&deviceURL, "/dev/%s", _physicalDeviceName);
	if(deviceURL)
	{
		fprintf(stderr, "%s = %s\n", deviceURL, deviceUDI);
		if(_physicalDeviceName && deviceUDI) 
			bRet = (strcmp(deviceURL, deviceUDI) == 0); 
		if(_curUDI && deviceUDI && !bRet) {
			bRet = (strcmp(_curUDI, deviceUDI) == 0); 
		}
		free(deviceURL);
		return bRet; 
	} else
		fprintf(stderr, "mediad: could not create deviceURI\n");
	return false;
}

bool device::Parse(char *s)
{
  char deviceName[256], name[256], mountpoint[256];
  int n;
  if((n=sscanf(s,"%255[^;];%255[^;];%255[^;];",deviceName,name,mountpoint))>=2) {
	setDevice(deviceName);
	// preset device mountpoint to be pmount conform
	asprintf(&_mountPoint, "/media/%s", _deviceName);
	if(n>=3) {
		if(_mountPoint) free(_mountPoint);
			_mountPoint = strdup(mountpoint);
	} else
		if(_name) free(_name);
			_name = strdup(name);
    return true;
   }
  return false;
}

const char* device::getMountPoint() const 
{ 
	return _mountPoint;
}

void device::setCurMediaType(const mediaType curMediaType) 
{ 
	_curMediaType = curMediaType; 
}

bool device::mount()
{
	char *cmd;
	int ret;
	asprintf(&cmd, "%s status /dev/%s", st_mountScript, getDeviceName());
	ret = system(cmd);
	printf("%s %d\n", cmd, ret);
	free(cmd);

	if (WEXITSTATUS(ret) == 1) {
		asprintf(&cmd, "%s %s /dev/%s", st_mountScript, "mount", getDeviceName());
		DPRINT("search executing command %s\n", cmd);
		ret = system(cmd);
		free(cmd);
		if (WEXITSTATUS(ret) == 0) {
			fprintf(stderr, "mounted successfully\n");
			_mounted = true;
		}
	} else
		_mounted = true;
	// get current mountpoint
	asprintf(&cmd, FINDMOUNTPOINT, getDeviceName());
	fprintf(stderr, "%s", cmd);
  	FILE *p = popen(cmd, "r");
  	if (p) {
   		char *s;
    		cReadLine r;
    		if ((s = r.Read(p)) != NULL) 
    			_mountPoint = strdup(s);
  	}
	free(cmd);
	return true;
}

bool device::umount()
{
	char *cmd;
	int ret;
	asprintf(&cmd, "%s %s %s", st_mountScript, "unmount", getMountPoint());
	DPRINT("search end executing command %s\n", cmd);
	ret = system(cmd);
	free(cmd);
	if (WEXITSTATUS(ret) == 0) {
		fprintf(stderr, "unmounted successfully\n");
		_mounted = false;
		return true;
	}

	return false;
}

bool device::isMounted() const
{
	return _mounted;
}

void device::setMountScript(const char *mountScript)
{
	if(device::st_mountScript)
		free(device::st_mountScript);
	device::st_mountScript = strdup(mountScript);
}

void device::setDevice(const char* deviceName) 
{
	char *buff = NULL;
	if(deviceName) {
		asprintf(&buff, "/dev/%s", deviceName);
		// check whether deviceName is a symbolic link
		struct stat fileStatus;
		if(lstat(buff, &fileStatus) != 0)
			fprintf(stderr, "stat error for file %s with errno %d\n", buff, errno);
		if(S_ISLNK(fileStatus.st_mode)) {
			fprintf(stderr, "is symbolic link\n");
			if(realpath(buff, _physicalDeviceName) == NULL) {
				fprintf(stderr, "Symblic links is invalid %s\n", buff);
				strcpy(_physicalDeviceName, deviceName);
			} else {
				strcpy(_physicalDeviceName, _physicalDeviceName+5);
				strcpy(_deviceName, deviceName);
			}
			asprintf(&_mountPoint, "/media/%s", _physicalDeviceName);
		} else {
			strcpy(_physicalDeviceName, deviceName);
			strcpy(_deviceName, deviceName);
		}
	} else {		
		_deviceName[0] = '\0';
		_physicalDeviceName[0] = '\0';
	}
	if(buff) free(buff);
}

void device::setInformation(const char* info)
{
	if(info)
		asprintf(&_information, "%s", info);
	else {
		if(_information)
			free(_information);
		_information = NULL;
	}
}

const char* device::getInformation() const
{
	if(_information)
		return _information;
	else
		return "";
}
// -- cFileSources --------------------------------------------------------------

bool deviceSources::Load(const char *filename, bool dummy)
{
  if(cConfig<device>::Load(filename,true)) {
    SetSource(First());
    return true;
    }
  return false;
}

device *deviceSources::FindSource(const char *dev)
{
  device *src = First();
  while(src) {
    if(*src == dev) return src;
    src=Next(src);
    }
  return 0;
}

