from ftplib import FTP
import filecmp
import os
import shutil

class LogsFileError(Exception):
	def __init__(self, value):
		self.value = value
		def __str__(self):
			return repr(self.value)


class Logs():

	serverFtp = 'logs.beamian.com'
	userFtp = 'logs@beamian.com'
	passwordFtp = "KG^Hn5B0RqBq+?I=F}"

	logDir = 'data'
	currentLogFile = 'data/log.csv'
	tempLogFile = 'data/log.temp_csv'
	backupLogFile = 'data/log.backup_csv'
	globalLogFile = 'data/global_log.csv'
	serverPath = 'logs/'

	def __init__(self, deviceId):
		#Create file in server with format eg B2001.txt
		self.deviceId = deviceId

		self.numberLogs = 0

		if os.path.isfile(self.currentLogFile):
			self.numberLogs = sum(1 for line in open(self.currentLogFile))

		print('Logs in file: ' + str(self.numberLogs))

	def numberLogsInFile(self):
		return self.numberLogs

	def getCurrentLogCount(self):
		#if os.path.isfile(self.currentLogFile):
		#	self.numberLogs = sum(1 for line in open(self.currentLogFile))
		print "log count: ", self.numberLogsInFile()

	def clearLogs(self):
		try:
			if os.path.isfile(self.currentLogFile):
				os.remove(self.currentLogFile)
			if os.path.isfile(self.tempLogFile):
				os.remove(self.tempLogFile)
			self.numberLogs = 0
		except Exception as e:
			pass

	def removeGlobalLog(self):
		try:
			if os.path.isfile(self.globalLogFile):
				os.remove(self.globalLogFile)
		except Exception as e:
			pass

	def sendLog(self, delete=True):

		if not os.path.isfile(self.currentLogFile):
			return True, 'No log file to upload'

		local_path  = self.currentLogFile
		try:
			ftp = FTP(self.serverFtp)
			ftp.login(self.userFtp, self.passwordFtp)
			ftpFiles = ftp.nlst(self.serverPath)

			fileName  = self.deviceId + '.csv'
			for i in range (0, 999):
				if fileName in ftpFiles:
					fileName = self.deviceId + "_" + str(i).zfill(3) + '.csv'
					continue
				else:
					break

			if i > 999:
				return False, 'Old log files in server'
			server_path = self.serverPath + fileName
			print('File Name Server' + fileName)
			f = open(local_path, 'rb')
			ftp.storbinary('STOR ' + server_path, f)
			f.close()
			ftp.quit()

			r, m = self.checkLog(server_path, self.currentLogFile)
			if r and delete:
				os.remove(self.currentLogFile)
				self.numberLogs = 0

			return r, m
		except Exception as e:
			errorMsg = str(e)
			return False, errorMsg[errorMsg.find("]") + 1:]

	def sendGlobalLog(self, delete=False):
		if not os.path.isfile(self.globalLogFile):
			return True, 'No global log file to upload'

		local_path  = self.globalLogFile
		try:
			ftp = FTP(self.serverFtp)
			ftp.login(self.userFtp, self.passwordFtp)
			ftpFiles = ftp.nlst(self.serverPath)

			fileName  = self.deviceId + '_global' + '.csv'
			for i in range (0, 999):
				if fileName in ftpFiles:
					fileName = self.deviceId + "_global_" + str(i).zfill(3) + '.csv'
					continue
				else:
					break

			if i > 999:
				return False, 'Old log files in server'

			server_path = self.serverPath + fileName
			print('File Name Server' + fileName)

			f = open(local_path, 'rb')
			ftp.storbinary('STOR ' + server_path, f)
			f.close()
			ftp.quit()
			r, m = self.checkLog(server_path,self.globalLogFile)
			if r and delete:
				os.remove(self.globalLogFile)

			return r, m
		except Exception as e:
			errorMsg = str(e)
			return False, errorMsg[errorMsg.find("]") + 1:]

	def checkLog(self, server_path, local_log_to_check):
		local_path = '/tmp/beamian_log'
		
		try:
			ftp = FTP(self.serverFtp)
			ftp.login(self.userFtp, self.passwordFtp)

			f = open(local_path, 'wb')
			ftp.retrbinary('RETR ' + server_path, f.write)
			f.close()
			ftp.quit()

			if filecmp.cmp(local_path,local_log_to_check):
				return True, 'Log file uploaded with success'
			else:
				return False, 'Local log file do not match with server'

		except Exception as e:
			errorMsg = str(e)
			return False, errorMsg[errorMsg.find("]") + 1:]

	def copyLog(self):
		if os.path.isfile(self.tempLogFile):
			os.remove(self.tempLogFile)

		if os.path.isfile(self.currentLogFile):
			shutil.copy(self.currentLogFile, self.tempLogFile)

		dir_fd = os.open(self.logDir,os.O_RDONLY)
		os.fsync(dir_fd)
		os.close(dir_fd)
		return

	def writeGlobalLog(self, formattedRow):
		# Write info to file
		with open(self.globalLogFile, 'a') as globalFile:
			globalFile.write(formattedRow + '\n')
			globalFile.flush()
			os.fsync(globalFile.fileno())
			globalFile.close()

	def writeLine(self, tag, timeStr , devID, typeStr):
		#tag, id, type are strings
		#timeStr is in format %Y-%m-%d %H:%M:%S
		if os.path.isfile(self.currentLogFile):
			print "log.csv size: ", os.path.getsize(self.currentLogFile)
		#save in csv format
		row = ",".join([tag,timeStr, devID, typeStr])
		self.writeGlobalLog(row)
		writeOK = False
		writeAttempts = 0
		while(not writeOK):
			self.copyLog()
			self.tryWriteFile(self.tempLogFile,row)
			writeAttempts+=1
			writeOK = self.checkFile(self.tempLogFile, tag, timeStr , devID, typeStr)
			if(writeAttempts>4):
				raise LogsFileError('log write file error')
				break
		if(writeOK):
			
			if os.path.isfile(self.currentLogFile):
				pre, ext = os.path.splitext(self.currentLogFile)
				os.rename(self.currentLogFile, pre + ".backup_csv") #silently overwrite file
			pre, ext = os.path.splitext(self.tempLogFile)
			os.rename(self.tempLogFile, pre + ".csv")
			dir_fd = os.open(self.logDir,os.O_RDONLY)
			os.fsync(dir_fd)
			os.close(dir_fd)
			print "synced logs to FS"
			


	def tryWriteFile(self,fileToWrite, formattedRow):
		# Write info to file
		if(fileToWrite.endswith(".temp_csv")):
			with open(fileToWrite, 'a') as f:
				f.write(formattedRow + '\n')
				f.flush()
				os.fsync(f.fileno())
				f.close()
				return

	def seekToLastLine(self,fileToSeek):
		with open(fileToSeek, "r") as f: 
			lines = f.readlines()
			last = lines[-1]
			return last

	def checkFile(self,fileToCheck, tag, date, id, tagType):
		try:
			if not os.path.exists(fileToCheck):
				print "checkfile file does not exist, ", fileToCheck
				return False	
			if(not fileToCheck.endswith(".temp_csv")):
				return False

			if(os.path.getsize(fileToCheck) == 0):
				print "checkfile file has 0 bytes, ", fileToCheck
				return False 

			line = self.seekToLastLine(fileToCheck)

			if line is None:
				print "checkfile line is None, ", fileToCheck
				return False
			if line is '':
				print "checkfile line is Empty, ", fileToCheck
				return False
			if(self.checkLine(line, tag, date, id, tagType)):
				return True
			else:
				return False
		except Exception as e:
			print 'Logs checkFile Exception' 
			print e
			return False
	
	def checkLine(self,lineToCheck, tag, date, id, tagType):
			sline = lineToCheck.rstrip()
			value_list = sline.split(",")
			
			if(len(value_list) is not 4):
				return False
			#tag 
			if(value_list[0] != tag):
				return False
			#date
			if(value_list[1] != date):
				return False
			
			if(not value_list[3].isalpha()):
				return False

			return True
