import numpy as np

def measure_vm(seg):
    vals = np.copy(seg)
    if len(vals) < 1:
        return 0, 0
    mean = np.mean(vals)
    vals -= mean
    rms = np.sqrt(np.mean(np.square(vals)))
    return mean, rms

########################################################################
# experiment-level metrics

def measure_blowout(v, idx0):
    return 1e3 * np.mean(v[idx0:])

def measure_electrode_0(curr, hz, t=0.005):
    n_time_steps = int(t * hz)
    # electrode 0 is the average current reading with zero voltage input
    # (ie, the equivalent of resting potential in current-clamp mode)
    return 1e12 * np.mean(curr[0:n_time_steps])

def measure_seal(v, curr, hz):
    t = np.arange(len(v)) / hz
    return 1e-9 * get_r_from_stable_pulse_response(v, curr, t)

def measure_input_resistance(v, curr, hz):
    t = np.arange(len(v)) / hz
    return 1e-6 * get_r_from_stable_pulse_response(v, curr, t)

def measure_initial_access_resistance(v, curr, hz):
    t = np.arange(len(v)) / hz
    return 1e-6 * get_r_from_peak_pulse_response(v, curr, t)


########################################################################

def get_r_from_stable_pulse_response(v, i, t):
    dv = np.diff(v)
    up_idx = np.flatnonzero(dv > 0)
    down_idx = np.flatnonzero(dv < 0)
#    print up_idx
#    print down_idx
#    print "-----"
    dt = t[1] - t[0]
    one_ms = int(0.001 / dt)
    r = []
    for ii in range(len(up_idx)):
        # take average v and i one ms before
        end = up_idx[ii] - 1
        start = end - one_ms
#        print "\tbase"
#        print "base interval: %d -> %d" % (start, end)
        avg_v_base = np.mean(v[start:end])
        avg_i_base = np.mean(i[start:end])
#        print "\tv: %g" % avg_v_base
#        print "\ti: %g" % avg_i_base
        # take average v and i one ms before end
        end = down_idx[ii]-1
        start = end - one_ms
#        print "\tsteady"
#        print "steady interval: %d -> %d" % (start, end)
        avg_v_steady = np.mean(v[start:end])
        avg_i_steady = np.mean(i[start:end])
#        print "\tv: %g" % avg_v_steady
#        print "\ti: %g" % avg_i_steady
        r_instance = (avg_v_steady-avg_v_base) / (avg_i_steady-avg_i_base)
#        print 1e-6*r_instance
        r.append(r_instance)
    return np.mean(r)

def get_r_from_peak_pulse_response(v, i, t):
    dv = np.diff(v)
    up_idx = np.flatnonzero(dv > 0)
    down_idx = np.flatnonzero(dv < 0)
    dt = t[1] - t[0]
    one_ms = int(0.001 / dt)
    r = []
    for ii in range(len(up_idx)):
        # take average v and i one ms before
        end = up_idx[ii] - 1
        start = end - one_ms
        avg_v_base = np.mean(v[start:end])
        avg_i_base = np.mean(i[start:end])
        # take average v and i one ms before end
        start = up_idx[ii]
        end = down_idx[ii] - 1
        idx = start + np.argmax(i[start:end])
        avg_v_peak = v[idx]
        avg_i_peak = i[idx]
        r_instance = (avg_v_peak-avg_v_base) / (avg_i_peak-avg_i_base)
        r.append(r_instance)
    return np.mean(r)





def get_last_vm_epoch(idx1, stim, hz):
    return idx1-int(0.500 * hz), idx1

def get_first_vm_noise_epoch(idx0, stim, hz):
    t0 = idx0
    t1 = t0 + int(0.0015 * hz)
    return t0, t1

def get_last_vm_noise_epoch(idx1, stim, hz):
    return idx1-int(0.0015 * hz), idx1

#def get_stability_vm_epoch(idx0, stim, hz):
def get_stability_vm_epoch(idx0, stim_start, hz):
    dur = int(0.500 * hz)
    #stim_start = find_stim_start(idx0, stim)
    if dur > stim_start-1:
        dur = stim_start-1
    elif dur <= 0:
        return 0, 0
    return stim_start-1-dur, stim_start-1

def find_stim_start(idx0, stim):
    # find stim start, using adaptation of nathan's numpy algorithm
    di = np.diff(stim)
    up_idx = np.flatnonzero(di > 0)
    down_idx = np.flatnonzero(di < 0)
    first = -1
    for i in range(len(up_idx)):
        if up_idx[i] >= idx0:
            first = up_idx[i]
            break
    for i in range(len(down_idx)):
        if down_idx[i] >= idx0 and down_idx[i] < first:
            first = down_idx[i]
            break
    # +1 to be first index of stim, not last index of pre-stim
    return first + 1

def find_stim_amplitude_and_duration(idx0, stim, hz):

    if len(stim) < idx0:
        idx0 = 0

    stim = stim[idx0:]

    peak_high = max(stim)
    peak_low = min(stim)

    # measure stimulus length
    # find index of first non-zero value, and last return to zero
    nzero = np.where(stim!=0)[0]
    if len(nzero) > 0:
        start = nzero[0]
        end = nzero[-1]
        dur = (end - start) / hz
    else:
        dur = 0
	
    dur = float(dur)

    if abs(peak_high) > abs(peak_low):
        amp = float(peak_high)
    else:
        amp = float(peak_low)

    return amp, dur

def find_stim_interval(idx0, stim, hz):
    stim = stim[idx0:]

    # indices where is the stimulus off
    zero_idxs = np.where(stim == 0)[0]

    # derivative of off indices.  when greater than one, indicates on period 
    dzero_idxs = np.diff(zero_idxs)
    dzero_break_idxs = np.where(dzero_idxs[:] > 1)[0]

    # duration of breaks
    break_durs = dzero_idxs[dzero_break_idxs]

    # indices of breaks
    break_idxs = zero_idxs[dzero_break_idxs] + 1

    # time between break onsets
    dbreaks = np.diff(break_idxs)

    if len(np.unique(break_durs)) == 1 and len(np.unique(dbreaks)) == 1:
        return dbreaks[0] / hz

    return None
