import numpy as np
import pandas as pd
import os
import re
import warnings

valid_types = ['csv', 'xls', 'xlsx', 'txt']
excel_types = ['xls', 'xlsx']
csv_types = ['csv', 'txt']
dlm_default = '\t'

label_dict = {'v':'v', 'ma':'i', 'a':'i', 's':'t', 'mv':'v', 'v vs. sce':'v', 'mv vs. sce':'v',
				'v vs. she':'v', 'mv vs. she':'v'}
default_labels = ['tintin', 'snowy', 'haddock', 'calculus', 'castafiore', 'thomson', 'thompson']

def check_type(filetype):
	"""
	Check if the filetype is currently supported for import

	fuelcell currently supports csv, xls, xlsx, and txt files

	Parameters
	___________
	filetype: str
		Filetype to be checked

	Returns
	________
	filetype: str
		If the given filetype string is valid, it is returned in lowercase and stripped of '.' characters 

	"""
	filetype = filetype.lower().replace('.', '')
	if filetype not in valid_types:
		raise ValueError('Supported filetypes ' + ', '.join(valid_types))
	return filetype

def check_list(var):
	"""
	Checks if var is a python list or numpy array

	Parameters
	___________
	var:
		variable to be checked

	Returns
	________
	result: bool
		True if var is a list or numpy array, False otherwise

	"""
	result = (type(var) == list) or (type(var) == np.ndarray)
	return result

def check_dict(var):
	"""
	Checks if var is a python dictionary

	Parameters
	___________
	var:
		variable to be checked

	Returns
	________
	result: bool
		True if var is a dict, False otherwise

	"""	
	result = type(var) == dict
	return result

def check_str(var):
	"""
	Checks if var is a string

	Parameters
	___________
	var:
		variable to be checked

	Returns
	________
	result: bool
		True if var is a string, False otherwise

	"""	
	result = type(var) == str
	return result

def check_float(var):
	"""
	Checks if var is a float

	Parameters
	___________
	var:
		variable to be checked

	Returns
	________
	result: bool
		True if var is a float, False otherwise

	"""	
	result = type(var) == float
	return result

def check_int(var):
	"""
	Checks if var is an integer

	Parameters
	___________
	var:
		variable to be checked

	Returns
	________
	result: bool
		True if var is an int, False otherwise

	"""	
	result = type(var) == int
	return result

def check_scalar(var):
	"""
	Checks if var is a scalar

	If the variable has a valid length (ie if len(var) is a valid call), it is considered not to be a scalar.

	Parameters
	___________
	var:
		variable to be checked.

	Returns
	________
	result: bool
		True if var is a scalar, False otherwise

	"""	
	try:
		len(var)
		return False
	except:
		return True

def check_labels(data):
	"""
	Parses column labels to determine the data stored in each column

	Current, voltage, time, etc. columns are determined from the units based on standard EC Lab conventions. If a column can be identified, its name is converted to the standard heading ('i' for current, 'v' for potential, etc.), otherwise, the namne is unchanged.

	Parameters
	___________
	data: DataFarame
		DataFrame in need of column identification

	Returns
	________
	newcols: list
		List containing the new column labels
	"""	
	cols = [c.lower() for c in data.columns]
	newcols = [];
	for c in cols:
		try:
			units = c.split('/')[1]
			if units in label_dict.keys():
				newcols.append(label_dict[units])
			else:
				newcols.append(c)
		except:
			newcols.append(c)
	return newcols

def get_files(path=None, pattern='', filetype=''):
	"""
	Find all files matching the desired criteria

	Determines which files in the specified directory match the given regular expression and/or are of the given filetype

	Parameters
	___________
	path: str, path object, or path-like (default=None)
		Directory in which files will be searched for. If unspecified, the current directory will be used.
	patter: str (default='')
		Regular expression. Only files matching this regular will be found. If unspecified, this parameter is ignored.
	filetype: str or regex (default='')
		Only files of this filetype will be found. If unspecified, filetype is ignored when finding files
	Returns
	________
	files: list
		List of all files in the specified directory matching the given criteria

	"""	
	files = os.listdir(path)
	files.sort()
	if pattern:
		files = [f for f in files if re.match(pattern, f)]
	if filetype:
		filetype = filetype.lower().replace('.', '')
		files = [f for f in files if re.match(r'.*\.'+filetype, f)]
	return files

def read_file(filename, dlm=dlm_default):
	"""
	Loads the specified file as a pandas DataFrame

	The specified file must be of one of the types supported for import. fuelcell currently supports csv, xls, xlsx, and txt files. If the file has a valid filetype but cannot be imported for some reason, a warning is raised.

	Parameters
	___________
	filename: str, path object, or path-like
		Name of a file in the current directory, or a complete path to the desired file.
	dlm: str (default='\t')
		Delimiting character if the file is a text file. Defaults to '\t' (tab-delimiting).

	Returns
	________
	name: str
		Filename with the filetype removed.
	data: DataFrame
		Pandas DataFrame containing the data read from the file.
	"""	
	data = None
	name = None
	try:
		name = os.path.basename(filename)
		name, filetype = name.split('.')
		filetype = check_type(filetype)
		if filetype in excel_types:
			data = pd.read_excel(filename)
		elif filetype in csv_types:
			if filetype == 'csv':
				data = pd.read_csv(filename)
			elif filetype == 'txt':
				data = pd.read_csv(filename, delimiter=dlm)
		return name, data
	except:
		if not os.path.isdir(filename):
			if filename.split('.')[0] in valid_types:
				warnings.warn(f'Unable to read {os.path.basename(filename)}', UserWarning)
	return name, data

def get_testdir():
	fcdir = os.path.dirname(os.path.realpath(__file__))
	datapath = os.path.join(fcdir, 'testdata')
	return datapath

def buildfilename(cellid, test, num=None, filetype='csv'):
	if num:
		filename = cellid + '_' + test + str(num) + '.' + filetype
	else:
		filename = cellid + '_' + test + '.' + filetype
	return filename