def calInfAccuray(modeChains, gpsTraces):
    
    timeTotal, timeInferred, distTotal, distInferred = 0, 0, 0, 0
    segTotal, segInferred, segWalkInfNonWalk, segNonWalkInfWalk = 0, 0, 0, 0
    for modeChain in modeChains:
        segTotal += 1
        walk, nonWalk, activity = 0, 0, 0
        for i in range(modeChain[0], modeChain[1]):
            timeTotal += ((gpsTraces[i+1][1] - gpsTraces[i][1])/1000.0)
            distTotal += (tripActivitySeparator.calDistance(gpsTraces[i][2:4], gpsTraces[i+1][2:4])/1609.34)            

            if gpsTraces[i][10] == 'Trip' and gpsTraces[i][11] == 'Walk':
                walk += 1
            elif gpsTraces[i][10] == 'Trip':
                nonWalk += 1
            else:
                activity += 1
                        
            if ((modeChain[-1] == 1 and gpsTraces[i][10] == 'Trip' and gpsTraces[i][11] == 'Walk') or
                    (modeChain[-1] == 0 and gpsTraces[i][10] == 'Trip' and gpsTraces[i][11] != 'Walk')):
                timeInferred += ((gpsTraces[i+1][1] - gpsTraces[i][1])/1000.0)
                distInferred += (tripActivitySeparator.calDistance(gpsTraces[i][2:4], gpsTraces[i+1][2:4])/1609.34)

        if ((max(walk, nonWalk, activity) == walk and modeChain[-1] == 1) 
                or (max(walk, nonWalk, activity) == nonWalk and modeChain[-1] == 0)):
            segInferred += 1
        elif (max(walk, nonWalk, activity) == walk and modeChain[-1] == 0):
            segWalkInfNonWalk += 1
        elif (max(walk, nonWalk, activity) == nonWalk and modeChain[-1] == 1):
            segNonWalkInfWalk += 1
                        
    return (timeTotal, timeInferred, distTotal, distInferred, 
            segTotal, segInferred, segWalkInfNonWalk, segNonWalkInfWalk)  
def inferModeChain(gpsTraces, trip, maxWalkSpeed, maxWalkAcceleration, 
        minSegmentDuration, minSegmentLength, gpsAccuracyThreshold):

    # Step 1: Label GPS points as walk points or non-walk points    
    walkDummy = {}
    i = trip[0]
    while i < trip[1]:
        start, end = i, i
        while end < trip[1] and (gpsTraces[end][4] > gpsAccuracyThreshold 
                or gpsTraces[end + 1][4] > gpsAccuracyThreshold
                or gpsTraces[end + 2][4] > gpsAccuracyThreshold):
            end += 1
        if start == end:
            features = determineFeatures(gpsTraces, i)            
            if features['Acceleration'] <= 945:
                if features['Heading Change'] <= 0.0000:
                    walkDummy[i] = 0
                elif features['Speed'] <= 8.0205:
                    walkDummy[i] = 1
                else:
                    walkDummy[i] = 0
            else:
                walkDummy[i] = 0
	    i += 1            
	else:
	    distance = tripActivitySeparator.calDistance(gpsTraces[start][2:4], gpsTraces[end][2:4])
	    time = (gpsTraces[end][1] - gpsTraces[start][1]) / 1000.0
	    speed = 2.23694 * (float(distance) / time)
	    dummy = int(speed < maxWalkSpeed)
            while i < end:
                walkDummy[i] = dummy
                i += 1
    print walkDummy 
    print
    
    # Step 2: Identify walk and non-walk segments as consecutive walk or non-walk points 
    modeChains = []
    beginSegment = trip[0]
    currentPoint = trip[0] + 1
    while currentPoint < trip[1]:
        if walkDummy[currentPoint] != walkDummy[beginSegment]:
            modeChains.append([beginSegment, currentPoint, int(walkDummy[beginSegment] != 0)])
            beginSegment = currentPoint
        currentPoint += 1
    modeChains.append([beginSegment, currentPoint, int(walkDummy[beginSegment] != 0)])
    print modeChains
    print

    # Step 3: If the time span of a segment is greater than minSegmentDuration milliseconds, label it 
    # as certain. If it is less than minSegmentDuration milliseconds, and its backward segment is certain,
    # merge it with the backward segment. If no certain backward segment exists, label the segment as 
    # uncertain, and save it as an independent segment. 
    newModeChains = []
    for i in range(0, len(modeChains)):
        if gpsTraces[modeChains[i][1]][1] - gpsTraces[modeChains[i][0]][1] >= minSegmentDuration:
            modeChains[i].append(1)
            newModeChains.append(modeChains[i])
        elif newModeChains and newModeChains[-1][-1] == 1:
            newModeChains[-1][1] = modeChains[i][1]
        else:
            modeChains[i].append(0)
            newModeChains.append(modeChains[i])
    modeChains = newModeChains
    print modeChains
    print

    # Step 4: Merge consecutive uncertain segments into a single certain segment. Calculate average
    # speed over segment and compare it against maxWalkSpeed to determine whether walk or non-walk.
    # Check if this segment exceeds minSegmentDuration milliseconds. If it doesn't, and there exists 
    # a certain forward segment, merge the new segment with this forward segment. 
    newModeChains, i = [modeChains[0][0:-1]], 1
    while i < len(modeChains) and modeChains[i][-1] == 0:
        i += 1
    if i > 1:
        newModeChains[0][1] = modeChains[i-1][1]
        distance = tripActivitySeparator.calDistance(gpsTraces[newModeChains[0][0]][2:4], gpsTraces[newModeChains[0][1]][2:4])
        time = (gpsTraces[newModeChains[0][1]][1] - gpsTraces[newModeChains[0][0]][1]) / 1000.0
        speed = 2.23694 * (float(distance) / time)
        newModeChains[0][-1] = int(speed < maxWalkSpeed)
    if i < len(modeChains) and modeChains[0][-1] == 0:
        time = (gpsTraces[newModeChains[0][1]][1] - gpsTraces[newModeChains[0][0]][1])
        if time < minSegmentDuration:
            modeChains[i][0] = trip[0]
            newModeChains = []
    while i < len(modeChains):
        newModeChains.append(modeChains[i][:-1])
        i += 1
    modeChains = newModeChains
    print modeChains
    print
        
    # Step 5: Merge consecutive walk segments and consecutive non-walk segments
    newModeChains = [modeChains[0]]
    for i in range(1, len(modeChains)):
        if modeChains[i][2] == newModeChains[-1][2]:
            newModeChains[-1][1] = modeChains[i][1]
        else:
            newModeChains.append(modeChains[i])
    modeChains = newModeChains    

    return modeChains
def lengthPoint(gpsTraces, j):
   return tripActivitySeparator.calDistance(gpsTraces[j][2:4], gpsTraces[j+1][2:4])