import types_g
import hextools
import logging
import os
import re
import shlex
import subprocess

TYPE_SIM = 0
TYPE_USIM = 1

#TODO: try to use types.fidFromPath(self.simFiles.findFileFromName('EF_ARR'))
EF_ARR_MF = 0x2F06
EF_ARR = 0x6F06

INVALID_RECORD_NUMBER = 0

DEFAULT_APP_AID = [0xA0,0x00,0x00,0x00,0x87,0x10,0x09,0xFF,0x81,0xFF,0xFF,0x89,0x06,0x02,0x00,0xFF]
DEFAULT_APP_LABEL = "simLAB"

# Selection mode 1
SELECT_DF_EF_MF        = 0b00000000
SELECT_CHILD_DF        = 0b00000001
SELECT_PARRENT_DF      = 0b00000011
SELECT_BY_DF_NAME      = 0b00000100
SELECT_BY_PATH_FROM_MF = 0b00001000
SELECT_BY_PATH_FROM_DF = 0b00001001

# Selection mode 2
SELECT_NO_DATA_RETURNED     = 0b00001100
SELECT_RETURN_FCP_TEMPLATE  = 0b00000100
SELECT_APP_ACTIVATION       = 0b00000000
SELECT_APP_TERMINATION      = 0b01000000
SELECT_APP_FIRST_OR_ONLY_OCCURENCE = 0b00000000
SELECT_APP_LAST_OCCURENCE   = 0b00000001

# Status - coding of P2
STATUS_SELECT_RESPONSE_RETURNED = 0b00000000
STATUS_DF_NAME_RETURNED = 0b00000001
STATUS_NO_DATA_RETURNED = 0b00001100

FILE_STRUCTURE_TRANSPARENT = 0
FILE_STRUCTURE_LINEAR_FIXED = 1
FILE_STRUCTURE_CYCLIC = 3
FILE_STRUCTURE_UNKNOWN = 4

FILE_TYPE_RFU = 0
FILE_TYPE_MF = 1
FILE_TYPE_DF = 2
FILE_TYPE_EF = 4

# Registered application provider IDentifier (RID)
RID_ETSI = 'A000000009'
RID_3GPP = 'A000000087'
RID_3GPP2 = 'A000000343'

# Access mode data objects
AM_DO_BYTE = 0x80
AM_DO_PROP = 0x9C
'''
1 0 0 0 1 - - -  (CLA), i.e., the value of CLA
1 0 0 0 - 1 - -  (INS), i.e., the value of INS
1 0 0 0 - - 1 -  (P1),  i.e., the value of P1
1 0 0 0 - - - 1  (P2),  i.e., the value of P2
'''
AM_DO_CLA  = 0b10001000
AM_DO_INS  = 0b10000100
AM_DO_P1   = 0b10000010
AM_DO_P2   = 0b10000001

# Dfs access mode byte
AM_DF_DELETE_FILE     = 0b01000000
AM_DF_TERMINATE       = 0b00100000
AM_DF_ACTIVATE_FILE   = 0b00010000
AM_DF_DEACTIVATE_FILE = 0b00001000
AM_DF_CREATE_FILE_DF  = 0b00000100
AM_DF_CREATE_FILE_EF  = 0b00000010
AM_DF_DELETE_CHILD    = 0b00000001

# Ef access mode - Access mode byte
AM_EF_DELETE          = 0b01000000
AM_EF_TERMINATE       = 0b00100000
AM_EF_ACTIVATE        = 0b00010000
AM_EF_DEACTIVATE      = 0b00001000
AM_EF_WRITE           = 0b00000100
AM_EF_UPDATE          = 0b00000010
AM_EF_READ            = 0b00000001
# Ef access mode - Command header description
# Command description by the value of INS
AM_EF_INCREASE        = types_g.iso7816.INCREASE
AM_EF_RESIZE          = types_g.iso7816.RESIZE_FILE

# Security condition data object
'''
'90'           0    -                               | Always
'97'           0    -                               | Never
'9E'           1    Security condition byte         | See Table 20
'A4'           Var. Control reference template      | External or user authentication depending on the usage qualifier
'B4','B6','B8' Var. Control reference template      | SM in command and / or response depending on the usage qualifier
'A0'           Var. Security condition data objects | At least one security condition shall be fulfilled (OR template)
'A7'           Var. Security condition data objects | Inversion of the security conditions (NOT template)
'AF'           Var. Security condition data objects | Every security condition shall be fulfilled (AND template)
'''
SC_DO_ALWAYS           = 0x90
SC_DO_NEVER            = 0x97
SC_DO_BYTE             = 0x9E
SC_DO_USER_AUTH_QC     = 0xA4
SC_DO_OR_TEMPLATE_TAG  = 0xA0
SC_DO_NOT_TEMPLATE_TAG = 0xA7
SC_DO_AND_TEMPLATE_TAG = 0xAF

#efArr offsets
AM_LENGTH_OFFSET        = 1
AM_BYTE_OFFSET          = 2
SC_DO_OFFSET            = 3
SC_DO_LENGTH_OFFSET     = 4
KEY_REF_TAG_OFFSET      = 5
KEY_DO_LENGTH_OFFSET    = 6
KEY_DO_VALUE_OFFSET     = 7

# Coding of life cycle status integer
LIFE_CYCLE_STATE_NO_INFO_GIVEN  = 0x00
LIFE_CYCLE_STATE_CREATION       = 0x01
LIFE_CYCLE_STATE_INIT           = 0x03
LIFE_CYCLE_STATE_OPER_ACTIVATED = 0x05
LIFE_CYCLE_STATE_OPER_DEACTIVATED = 0x04
LIFE_CYCLE_STATE_TERMINATION    = 0x0C

#key reference tag
KEY_REF_TAG = 0x83

#key reference value
'''
01-08 PIN1
81-88 PIN2
0A-0E ADM1-ADM5
'''
KEY_REF_PIN1  = 0x01
KEY_REF_PIN2  = 0x81
KEY_REF_ADM1  = 0x0A
KEY_REF_ADM2  = 0x0B
KEY_REF_ADM3  = 0x0C
KEY_REF_ADM4  = 0x0D
KEY_REF_ADM5  = 0x0E
KEY_REF_PIN_UNIV  = 0x11

#usage qualifier tag
UQ_TAG = 0x95

#key Reference data user knowledge based
'''
- - - - 1 - - - - use the PIN for verification (Key Reference data user knowledge based)
'''
PIN_VERIFY = 0x8

#access condition
AC_ALWAYS = 0x00
AC_CHV1   = 0x01
AC_CHV2   = 0x02
AC_RFU    = 0x03
AC_ADM1   = 0x04
AC_ADM2   = 0x05
AC_ADM3   = 0x06
AC_ADM4   = 0x07
AC_ADM5   = 0x08
AC_NEVER  = 0x0F
AC_UNKNOWN= 0xFF

# Application tags
APP_TEMPLATE_TAG = 0x61
APP_IDENTIFIER_TAG = 0x4F # AID
APP_LABEL_TAG = 0x50
APP_PATH_TAG = 0x81
# and some more

# manage channel
MANAGE_CHANNEL_OPEN = 0x00
MANAGE_CHANNEL_CLOSE = 0x80 # (1<<8)
MAX_LOGICAL_CHANNELS = 4
MAX_ORIGIN_CHANNELS = 4

#TODO: refactor, same as types_g.selectTag
FILE_LENGTH_EXCLUDING_SI_TAG = 0x80
FILE_LENGTH_INCLUDING_SI_TAG = 0x81
PS_DO_TAG                    = 0x90

#CSG
CSG_TEMPLATE_TAG    = 0xA0
CSG_PLMN_TAG        = 0x80
CSG_INFORMATION_TAG = 0x81

FILE_FORMAT_UNKNOWN        = 0
FILE_FORMAT_ID             = 1
FILE_FORMAT_NAME           = 2
FILE_FORMAT_PATH_ABSOLUTE  = 3
FILE_FORMAT_DF_CURRENT     = 4
FILE_FORMAT_DF_PARENT      = 5
FILE_FORMAT_ADF_ID         = 6
FILE_FORMAT_ADF_NAME       = 7

ARR_ALL_ALWAYS = [0x80, 0x01, 0x5F, 0x90, 0x00, 0x84, 0x01, 0x32,
                  0x90, 0x00, 0x84, 0x01, 0xD4, 0x90, 0x00]
# Limitted access - ALWAYS for Read/DeleteChild and Update/CreateEf commands
ARR_CUSTOM =     [0x80, 0x01, 0x03, 0x90, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]

keyRefDict = {AC_ALWAYS : SC_DO_ALWAYS,
              AC_CHV1 : KEY_REF_PIN1,
              AC_CHV2 : KEY_REF_PIN2,
              AC_ADM1 : KEY_REF_ADM1,
              AC_ADM2 : KEY_REF_ADM2,
              AC_ADM3 : KEY_REF_ADM3,
              AC_ADM4 : KEY_REF_ADM4,
              AC_ADM5 : KEY_REF_ADM5,
              AC_NEVER : SC_DO_NEVER}

#FCI
FCP_TEMPLATE_TAG = 0x62
FDM_TEMPLATE_TAG = 0x64
FCI_TEMPLATE_TAG = 0x6F

#For a MF / DF / ADF / EF creation:
#FIXME: same as types_g.selectTag plus some additional tags
DATA_CODING_BYTE                = 0x21
FILE_SIZE_TAG                   = 0x80
TOTAL_FILE_SIZE_TAG             = 0x81
FDB_TAG                         = 0x82 # (M) File Descriptor
FID_TAG                         = 0x83
DF_NAME_TAG                     = 0x84
PROPRITEARY_NO_BERTLV_TAG       = 0x85
PROPRITEARY_SECURITY_ATTRIB_TAG = 0x86
EF_FCI_EXTENSION                = 0x87
SFI_TAG                         = 0x88
LCSI_TAG                        = 0x8A # (M)
SECURITY_ATTRIB_COMPACT_TAG     = 0x8B # (M)*
SECURITY_ATTRIB_REF_EXPANDED    = 0x8C # (M)*
PROPRIETARY_TAG                 = 0xA5 # (O)
SECURITY_ATTRIB_EXPANDED_TAG    = 0xAB # (M)*
PIN_STATUS_TEMPLETE_DO_TAG      = 0xC6


DF_AID_TAG                      = 0x84 # (O)
# *Exactly one of the tags should be present

# Proprietary information ('A5') - all optional
SPECIAL_FILE_INFORMATION        = 0xC0
FILLING_PATTERN                 = 0xC1
REPEAT_PATTERN                  = 0xC2
MAXIMUM_FILE_SIZE               = 0x86
FILE_DETAILS                    = 0x84
GSM_ACCESS_CONDITION_TAG        = 0x90
FILE_SHARING_INFO_TAG           = 0x91
EFARR_ACCESS_RULE_SE01_TAG      = 0xAA
EFARR_ACCESS_RULE_SE00_TAG      = 0xAB

#network name
FULL_NW_NAME_TAG                = 0x43
SHORT_NW_NAME_TAG               = 0x45
ADDITIONAL_INFORMATION_PLMN_TAG = 0x80

def cla(apdu):
    return apdu[0]

def ins(apdu):
    return apdu[1]

def p1(apdu):
    return apdu[2]

def p2(apdu):
    return apdu[3]

def p3(apdu):
    try:
        return apdu[4]
    except:
        return None

def dataLc(apdu):
    try:
        return apdu[5 : (5 + p3(apdu))]
    except:
        return None

def le(apdu):
    leIdx = 5 + p3(apdu)
    if len(apdu) > leIdx:
        return apdu[leIdx]
    else:
        return None

def binaryOffset(apdu):
    if p1(apdu) & types_g.binaryCmdP1.SFI_MODE:
        offset = p2(apdu)
    else:
        offset = (p1(apdu) << 8) + p2(apdu)
    return offset

def channel(apdu):
    return apdu[0] & 0b00000011

def returnType(apdu):
    return p2(apdu) & 0b00001100

def appControl(apdu):
    return p2(apdu) & 0b11110000

def fileId(apdu):
    return apdu[-2] * 256 + apdu[-1]

def aid(apdu):
    return dataLc(apdu)

def insName(apdu):
    _ins = ins(apdu)
    try:
        return types_g.iso7816[_ins]
    except:
        return "%02X" %_ins

def sw1(rapdu):
    return rapdu[-2]

def sw2(rapdu):
    return rapdu[-1]

def sw(rapdu):
    return (sw1(rapdu)<<8) + sw2(rapdu)

def swName(sw1, sw2):
    if sw1 == None and sw2 == None:
        return None,  None
    sw = packSw(sw1, sw2)
    try:
        swName = types_g.sw[sw]
    except:
        swName = "%04X" %sw

    try:
        sw1Name = types_g.sw1[sw1]
    except:
        sw1Name = "%02X" %sw1
    return sw1Name, swName

def assertSw(sw1, sw2, checkSw=None, checkSw1=None, log=True, raiseException=False):
    sw1Name, swReceived = swName(sw1, sw2)
    if (checkSw and
        checkSw != swReceived and
        not (checkSw == types_g.sw[types_g.sw.NO_ERROR] and sw1 == types_g.sw1.NO_ERROR_PROACTIVE_DATA)):
        if checkSw != swReceived:
            errorString = "Incorrect SW: %s, expecting: %s. SW1=%s" %(swReceived, checkSw, sw1Name)
            if raiseException:
                raise Exception(errorString)
            else:
                if log:
                    logging.error(errorString)
                else:
                    logging.debug(errorString)
                return True
    elif checkSw1:
        if checkSw1 != sw1Name:
            errorString = "Incorrect SW1: %s, expecting: %s. SW=%s" %(sw1Name, checkSw1, swReceived)
            if raiseException:
                raise Exception(errorString)
            else:
                if log:
                    logging.error(errorString)
                else:
                    logging.debug(errorString)
                return True
    return False

def swNoError(rapdu):
    if sw1(rapdu) == 0x91 or (sw1(rapdu) == 0x90 and sw2(rapdu) == 0x00):
        return True
    else:
        return False

def responseData(rapdu):
    return rapdu[0:-2]

def packSw(sw1, sw2):
    return (sw1<<8) + sw2

def unpackSw(sw):
    sw1 = sw >> 8
    sw2 = sw & 0x0F
    return sw1, sw2

def removeTrailingBytes(array, pattern):
    i = 0
    for byte in array:
        if byte == pattern:
            break
        i += 1
    return array[0:i]

def addTrailingBytes(hexStr, pattern, size):
    if len(hexStr) % 2:
        hexStr += 'F'
    length = size - len(hexStr)/2
    if length > 0:
        hexStr += ("%02X" %pattern) * length
    return hexStr

def getEfAccessMode(byte):
    accesMode = []
    '''
    0 1 - - - - - - DELETE FILE
    0 - 1 - - - - - TERMINATE EF
    0 - - 1 - - - - ACTIVATE FILE
    0 - - - 1 - - - DEACTIVATE FILE
    - - - - - 1 - - WRITE BINARY, WRITE RECORD, APPEND RECORD
    - - - - - - 1 - UPDATE BINARY, UPDATE RECORD, ERASE BINARY, ERASE RECORD(S)
    - - - - - - - 1 READ BINARY, READ RECORD (S), SEARCH BINARY, SEARCH RECORD
    '''
    if byte & AM_EF_DELETE:
        accesMode.append(AM_EF_DELETE)
    if byte & AM_EF_TERMINATE:
        accesMode.append(AM_EF_TERMINATE)
    if byte & AM_EF_ACTIVATE:
        accesMode.append(AM_EF_ACTIVATE)
    if byte & AM_EF_DEACTIVATE:
        accesMode.append(AM_EF_DEACTIVATE)
    if byte & AM_EF_WRITE:
        accesMode.append(AM_EF_WRITE)
    if byte & AM_EF_UPDATE:
        accesMode.append(AM_EF_UPDATE)
    if byte & AM_EF_READ:
        accesMode.append(AM_EF_READ)
    return accesMode

def getValue(data, keepData=True):
    if keepData:
        dataTmp = list(data)
    else:
        dataTmp = data
    length = dataTmp.pop(0)
    if not length:
        return None
    responseData = dataTmp[:length]
    del dataTmp[:length]
    return responseData

def parseTlvMain(data, mainTlv, tag):
    dataTmp = list(data)
    tlvTag = dataTmp.pop(0)
    if tlvTag != mainTlv:
        return None
    length = dataTmp.pop(0) # length
    return parseTlv(dataTmp, tag)

def parseTlv(data, tag, keepData=True):
    if keepData:
        dataTmp = list(data)
    else:
        dataTmp = data

    while len(dataTmp):
        tlvTag = dataTmp.pop(0) # local info tag
        length = dataTmp.pop(0) # length
        if length:
            responseData = dataTmp[:length]
            del dataTmp[:length]
        else:
            responseData = []
        if tag == tlvTag:
            return responseData
    return None

def addTlv(data, tag, parameters):
    data.append(tag)
    data.append(len(parameters))
    data.extend(parameters)
    return data

def addMainTlv(data, tag):
    dataLength = len(data)/2
    data = "%02X%02X%s" %(tag, dataLength, data)
    return data

def parseFcpTlv(data, tag):
    return parseTlvMain(data, FCP_TEMPLATE_TAG, tag)

def parseCsgTlv(data, tag):
    return parseTlvMain(data, CSG_TEMPLATE_TAG, tag)

def getAidFromDirRecord(data):
    return parseTlvMain(data, APP_TEMPLATE_TAG, APP_IDENTIFIER_TAG)

def getKeyRefFromAm(value):
    ''' The KEY_REF_TAG ('83') tag, defining which Secret Code is to be verified '''
    lenKeyRef = value.pop(0)
    if lenKeyRef:
        keyRef = value.pop(0)
        uqTag = value.pop(0)
        if uqTag != UQ_TAG:
            logging.error("User qualifier tag %02X not expected" %uqTag)

        uqLen = value.pop(0)
        if uqLen:
            pinVerify = value.pop(0)
            if pinVerify != PIN_VERIFY:
                logging.error("PIN verify tag %02X not expected" %pinVerify)
    return keyRef

def getKeyFromUserAuthScdo(value):
    ''' Parse SC_DO_USER_AUTH_QC ('A4') tag '''
    keyRefTag = value.pop(0)
    if keyRefTag not in [KEY_REF_TAG]:
        logging.error("Key reference tag %02X not expected" %keyRefTag)
    return getKeyRefFromAm(value)

def parseEfArrRuleAmDo(value):
    accessModes = []
    keys = []
    template = None

    amDoType = value[0]
    if amDoType == AM_DO_BYTE:
        amDoByte = parseTlv(value, AM_DO_BYTE, keepData=False)
        accessModes = getEfAccessMode(amDoByte[0])
    elif amDoType == AM_DO_INS:
        amDoIns = parseTlv(value, AM_DO_INS, keepData=False)
        accessModes.append(amDoIns[0]) # 'D4' - RESIZE or '32' - INCREASE
    else:
        #TODO: implement
        logging.error("Access mode tag %02X not implemented" %amDoType)
        nextAmDo = len(value)
        return nextAmDo, accessModes, keys

    scDo = value.pop(0)
    length = value.pop(0)
    nextAmDo = value[length:]

    if scDo in [SC_DO_ALWAYS, SC_DO_NEVER]:
        keys.append(scDo)
    elif scDo == SC_DO_USER_AUTH_QC:
        keys.append(getKeyFromUserAuthScdo(value))
    elif scDo in [SC_DO_OR_TEMPLATE_TAG,
                SC_DO_NOT_TEMPLATE_TAG,
                SC_DO_AND_TEMPLATE_TAG]:
        template = scDo
        while(value):
            scDo = value.pop(0)
            length = value.pop(0)
            if scDo == SC_DO_USER_AUTH_QC:
                keys.append(getKeyFromUserAuthScdo(value))
            else:
                break
    else:
        logging.error("Security condition tag %02X not supported" %scDo)

    return nextAmDo, accessModes, keys, template

def parseEfArrRule(value):
    access = {}
    amDo = list(value)

    while amDo[0] != 0xFF:
        amDo, accessModes, keys, condMode = parseEfArrRuleAmDo(amDo)
        for accessMode in accessModes:
            access[accessMode] = [keys, condMode]
        if not amDo:
            break;
    return access

def getFileStructureFromFileDescriptor(fileDecriptor):
    structureBits = fileDecriptor & types_g.fileDecriptorMask.EF_STRUCTURE
    if structureBits ==  types_g.fileDescriptor.TRANSPARENT_STRUCTURE:
        structure = FILE_STRUCTURE_TRANSPARENT
    elif structureBits ==  types_g.fileDescriptor.LINEAR_FIXED_STRUCTURE:
        structure = FILE_STRUCTURE_LINEAR_FIXED
    elif structureBits ==  types_g.fileDescriptor.CYCLIC_STRUCTURE:
        structure = FILE_STRUCTURE_CYCLIC
    else:
        structure = FILE_STRUCTURE_UNKNOWN
    return structure


def getAccessConditions(arrValue, accessMode):
    conditions = []
    accesses = parseEfArrRule(arrValue)
    try:
        access = accesses[accessMode]
        keys = access[0]
        condMode = access[1] # template (and, or, not)
    except:
        keys = [SC_DO_NEVER]
        condMode = None

    for key in keys:
        if key == SC_DO_ALWAYS:
            condition = AC_ALWAYS
        elif key == KEY_REF_PIN1:
            condition = AC_CHV1
        elif key == KEY_REF_PIN2:
            condition = AC_CHV2
        elif key == KEY_REF_ADM1:
            condition = AC_ADM1
        elif key == KEY_REF_ADM2:
            condition = AC_ADM2
        elif key == KEY_REF_ADM3:
            condition = AC_ADM3
        elif key == KEY_REF_ADM4:
            condition = AC_ADM4
        elif key == KEY_REF_ADM5:
            condition = AC_ADM5
        elif key == SC_DO_NEVER:
            condition = AC_NEVER
        else:
            raise Exception("Unknown key %02X" %key)
        conditions.append(condition)

    return conditions, condMode

def validPathFormat(path):
    for _file in path.split("/")[0:]:
        if not _file:
            #root dir '/'
            continue
        if _file in ["/", "..", "."]:
            continue
        elif _file.startswith("EF_") or _file.startswith("DF_"):
            continue
        elif _file.startswith("ADF_"):
            continue
        try:
            int(_file, 16)
            if len(_file) != 4:
                logging.warning("File: %s has incorrect length, expected 4" %_file)
                return False
            continue
        except:
            return False
    return True

def getAdfId(adfName):
    adfIdRe = re.compile("ADF(\d)", re.IGNORECASE)
    adfId = adfIdRe.search(adfName)
    if not adfId:
        logging.warning("ADF name not expected: %s" %adfName)
        return None
    return int(adfId.group(1))

def getFileNameFormat(path):
    if not path:
        raise Exception("path is empty")
    path = path.upper()
    if not validPathFormat(path):
        return FILE_FORMAT_UNKNOWN
    if path.startswith("EF_") or path.startswith("DF_"):
        format = FILE_FORMAT_NAME
    elif path.startswith("ADF") and path[3].isdigit():
        format = FILE_FORMAT_ADF_ID
    elif path.startswith("ADF_"):
        format = FILE_FORMAT_ADF_NAME
    elif path.startswith("/"):
        format = FILE_FORMAT_PATH_ABSOLUTE
    elif path.startswith("./") or path == ".":
        format = FILE_FORMAT_DF_CURRENT
    elif path.startswith("../") or path == "..":
        format = FILE_FORMAT_DF_PARENT
    else:
        format = FILE_FORMAT_ID
    return format

def isFidAdf(fid):
    fid = fid.upper()
    return fid.startswith("ADF")

def getAidFromData(data):
    return parseFcpTlv(data, types_g.selectTag.DF_NAME)

def getSfiFromData(data):
    sfi = parseFcpTlv(data, types_g.selectTag.SHORT_FILE_IDENTIFIER)
    if not sfi:
        return 0
    return sfi[0]

def getFileLength(data):
    tagData = parseFcpTlv(data, FILE_LENGTH_EXCLUDING_SI_TAG)
    if tagData == None:
        logging.error("BINARY_LENGTH_TAG not found in FCI")
        return None
    length = tagData[1]
    return length

def getArrFileFromData(data):
    arr = parseFcpTlv(data, SECURITY_ATTRIB_COMPACT_TAG)
    if not arr:
        return None, None
    arrFile = "%02X%02X" %(arr[0], arr[1])
    arrRecord = arr[2]
    return arrFile, arrRecord

def getSecurityAttribFromData(data):
    secAtrr = parseFcpTlv(data, SECURITY_ATTRIB_EXPANDED_TAG)
    return secAtrr

def fidFromPath(path):
    if path == "/":
        return "3F00"
    elif "/" in path:
        if path[-1] == '/':
            path = path[0:-1]
        files = path.split("/")[0:]
        fid = files[-1]
    else:
        fid = path
    return fid

def previousFidFromPath(path):
    if "/" in path:
        files = path.split("/")[1:]
        if len(files) > 1:
            fid = files[-2]
            return fid
    return None

def parentDirFromPath(path):
    if '/' in path:
        if path[-1] == '/':
            path = path[0:-1]
        parrent = "/".join(path.split("/")[0:-1])
        if not parrent:
            parrent = '/'
        return parrent
    else:
        return "../"

def addToPath(path, fileName):
    if (path and
        fileName and
        fileName != "/" and
        path[-1] != "/"):
        path += "/"
    if (path != "/" or fileName != "/"):
        path += fileName
    return path

def getFilesFromPath(path):
    return path.strip("/").split("/")

def getParamValue(data, paramName, splitCharacter=',', separator='='):
    parameters = data.split(splitCharacter)
    for parameter in parameters:
        if parameter.find(paramName) != -1:
            value = re.search("%s%s(.*)" %(paramName, separator), parameter).group(1)
            if value == 'None':
                return None
            else:
                return value
    return None

#get data value returned by sim_shell
def getDataValue(out):
    return re.search("data (.*)", out).group(1)

def getKeyFromDictValue(dictionary, value):
    _dictionary = dict((v,k) for k, v in dictionary.iteritems())
    return _dictionary[value]

### Misc ###
def bytes2int(bytes):
    size = len(bytes)
    return sum(bytes[i] << ((size-i-1) * 8) for i in range(size))

def cmpBitwise(value1, value2, mask=None):
    if mask == None: mask=value2
    if value1 & mask == value2:
        return True
    return False

def isSublist(list1, list2):
    lengthList1 = len(list1)
    lengthList2 = len(list2)
    if lengthList1 > lengthList2:
        return False
    return any(list1 == list2[i:(lengthList1+i)] for i in xrange(lengthList2 - (lengthList1+1)))

def killProcess(name, signal=15):
    if os.name != 'posix':
        #cmd = 'taskkill /f /im ' + name
        cmd = 'taskkill /im /t' + name
    else:
        cmd = "killall -%d %s" %(signal, name)
    p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p.communicate()
    return out,err