def get_values(*names):
    import json
    _all_values = json.loads("""{"numSamps":96,"p300m":"p300_multi_gen2","pipMnt":"right","mag_gen":"magnetic module gen2"}""")
    return [_all_values[n] for n in names] #change number of samples per protocol if needed

from opentrons import types
import math
metadata = {
    'protocolName': 'OT2_Omegabiotekfecal_v4.0',
    'protocolVersion: v4.0'
    'changes from v3.9: Optimised for OBiotek Magbead 96 Stool Kit on June 20,2023 by getting rid of unnecessary spaces, and got rid of +1 in line 22 on August 3, 2023'
    'Organization/Author': 'In situ Lab <lalabmanager@insitulabs@org>, San Diego Wildlife Alliance Population Sustainability Molecular Ecology Lab',
    'source': 'Protocol Library Modified from Chaz <chaz@opentrons.com> and Gylianne <support@opentrons.com>',
    'apiLevel': '2.5'
}

def run(protocol):
    [numSamps, p300m, pipMnt, mag_gen] = get_values(  # noqa: F821
        'numSamps', 'p300m', 'pipMnt', 'mag_gen')
    light = protocol.set_rail_lights(True)
    #load labware and pipettes
    numCols = math.ceil((numSamps/8)+1) 
    tips200 = [
        protocol.load_labware(
            'opentrons_96_tiprack_300ul', s) for s in [
                '8', '5', '9', '6'
                ]
            ]
    allTips = [t for rack in tips200 for t in rack.rows()[0]]
    buffer_tips = allTips[:1]
    mixTips = allTips[1:numCols]
    trashTips = allTips[numCols:]
    p300 = protocol.load_instrument(p300m, pipMnt, tip_racks=tips200)
    magdeck = protocol.load_module(mag_gen, '7')
    magheight = 4.5 if mag_gen == 'magdeck' else 4   #changed from magheight = 13.7 if mag_gen == 'magdeck' else 6.85
    magplate = magdeck.load_labware('vwr_96_wellplate_1000ul')
    flatplate1 = protocol.load_labware('nest_96_wellplate_100ul_pcr_full_skirt','3', 'first elution') #first was spelled wrong, changed this
    flatplate2 = protocol.load_labware('denvillewithaxygenbase_96_wellplate_200ul','2')
    wasteres = [protocol.load_labware(
                'nest_1_reservoir_195ml', s, 'Liquid Waste') for s in [10, 11]]
    waste1 = wasteres[0]['A1'].top()
    waste2 = wasteres[1]['A1'].top()
    trough2 = protocol.load_labware(
                'nest_12_reservoir_15ml', '1', '12-Reservoir with Reagents')
    trough = protocol.load_labware(
                'nest_12_reservoir_15ml', '4', '12-Reservoir with Reagents')
    lysite = flatplate2.rows()[:numCols]
    buffer = [w for w in trough.wells()[:3] for _ in range(4)][:numCols]
    wb1 = [w for w in trough.wells()[4:8] for _ in range(3)][:numCols]
    wb2 = [w for w in trough.wells()[8:] for _ in range(3)][:numCols]
    ethanol1 = [w for w in trough2.wells()[:4] for _ in range(3)][:numCols]
    ethanol2 = [w for w in trough2.wells()[4:8] for _ in range(3)][:numCols]
    water = trough2['A12']
    magsamps = magplate.rows()[0][:numCols]
    elutes = flatplate1.rows()[0][:numCols]
    elutes2 = flatplate2.rows()[0][:numCols] # check this again, same as next row.
    lysite = flatplate2.rows()[0][:numCols]
    sides = [1, -1]*6
   
    p300.flow_rate.aspirate = 20   #changed from 50
    p300.flow_rate.dispense = 150
    p300.flow_rate.blow_out = 300
    def well_mix(reps, loc, vol, s):
        loc1 = loc.bottom().move(types.Point(x=s, y=0, z=0.8))
        loc2 = loc.bottom().move(types.Point(x=s, y=0, z=5.5))
        p300.aspirate(20, loc1)
        mvol = vol-20
        for _ in range(reps-1):
            p300.aspirate(mvol, loc1)
            p300.dispense(mvol, loc2)
        p300.dispense(20, loc2)
    def init_well_mix(reps, loc, vol, s):
        loc1 = loc.bottom().move(types.Point(x=s, y=0, z=0.8))
        loc2 = loc.bottom().move(types.Point(x=s, y=0, z=5.5))
        loc3 = loc.bottom().move(types.Point(x=-s, y=0, z=0.8))
        loc4 = loc.bottom().move(types.Point(x=-s, y=0, z=5.5))
        p300.aspirate(20, loc1)
        for _ in range(reps-1):
            p300.aspirate(vol, loc1)
            p300.dispense(vol, loc4)
            p300.aspirate(vol, loc3)
            p300.dispense(vol, loc2)
        p300.dispense(20, loc2)

    tipNum = 0
    def _drop_tip():
        nonlocal tipNum
        p300.drop_tip(trashTips[tipNum])
        tipNum += 1
    tipNum2 = 0
    def _pick_tip():
        nonlocal tipNum2
        p300.pick_up_tip(trashTips[tipNum2])
        tipNum2 += 1
    tipNum3 = 0
    def _pick_buffer_tip():
        nonlocal tipNum3
        p300.pick_up_tip(buffer_tips[tipNum3])
        tipNum3 += 0
       
    protocol.comment('Your extraction is going to start')
   
   # transfer 310ul of XP2 Binding Buffer + Magbind particles (total we have is 600 XP2 + 20 beads)
    def viral_step(src, dest, msg):
        protocol.comment(f'{msg}')
        _pick_buffer_tip()
        for well, s in zip(magsamps, src):
            for _ in range(1):#changed to 1 time
                p300.aspirate(150, s)
                p300.dispense(150, well.top(-5))
                p300.aspirate(10, well.top(-5))
            p300.aspirate(160, s)
            p300.dispense(180, well.top(-10))
            p300.blow_out()
            p300.aspirate(10, well.top(-5))
            protocol.delay(seconds=1)
        p300.return_tip()
        #mix magbeads for 10 minutes
        protocol.comment('Mixing samples+buffer+beads')
        for well, tip, side in zip(magsamps, mixTips, sides):
            p300.pick_up_tip(tip)
            init_well_mix(8, well, 130, side)
            init_well_mix(8, well, 130, side)
            p300.blow_out()
            p300.return_tip()
    viral_step(buffer,magsamps,'First time adding XP2 binding buffer + beads')
   
   
    magdeck.engage(height=magheight)
    protocol.comment('Incubating on magdeck for 10')
    protocol.delay(minutes=10) #CHANGED FOR WATER RUN
    # Step 5 - Remove supernatant
    def supernatant_removal(vol, src, dest, s, zz=0.5):
        p300.flow_rate.aspirate = 20
        tvol = vol
        asp_ctr = 0
        while tvol > 180:
            p300.aspirate(
                180, src.bottom().move(types.Point(x=-s, y=0, z=zz)))
            p300.dispense(180, dest)
            p300.aspirate(10, dest)
            tvol -= 180
            asp_ctr += 1
            if zz > 10:
                zz -= 10
        p300.aspirate(
            tvol, src.bottom().move(types.Point(x=-s, y=0, z=0.5)))
        dvol = 10*asp_ctr + tvol
        p300.dispense(dvol, dest)
        p300.aspirate(10, dest) #*added to prevent dripping on the last round of supernatant removal*
        p300.flow_rate.aspirate = 20 #changed from 50
   
    # protocol.comment('Removing supernatant:') # why is this hashed out??
    for well, tip, side in zip(magsamps, mixTips, sides):
        p300.pick_up_tip(tip)
        supernatant_removal(510, well, waste1, side, zz=15) #changed from 650 to 510
        p300.blow_out() #added to prevent dripping
        p300.return_tip()
    magdeck.disengage()
    #adding 200ul more of lysate to the magnetic block and deep well plate
    protocol.comment('Adding second lysate volume to initial samples')
    for well, reagent, tip, side in zip(magsamps, lysite, mixTips, sides):
        p300.pick_up_tip(tip)
        p300.aspirate(200, reagent)
        p300.dispense(220, well.top(-10))
        well_mix(4, well, 100, side)
        p300.blow_out()
        p300.aspirate(20, well.top(-5))
        p300.return_tip()
   
    viral_step(buffer,magsamps,'Second time adding XP2 binding buffer + beads')
   
    magdeck.engage(height=magheight)
    protocol.comment('Incubating on magdeck for 10')
    protocol.delay(minutes=10) #CHANGED FOR WATER RUN
   
    for well, tip, side in zip(magsamps, mixTips, sides):
        p300.pick_up_tip(tip)
        supernatant_removal(510, well, waste1, side, zz=15) #changed to 510 from 650
        p300.return_tip()
       
    magdeck.disengage()
   
    def wash_step(src, mtimes, wasteLoc, msg):
        protocol.comment(f'Wash Step {msg} -  Adding to samples:')
        p300.pick_up_tip()
        for well, s in zip(magsamps, src):
            for _ in range(2):
                p300.aspirate(133, s) #**changed from 500 to 400 uL**
                p300.dispense(133, well.top(-3))
                p300.aspirate(10, well.top(-3))
            p300.aspirate(133, s)
            p300.dispense(153, well.top(-3))
            protocol.delay(seconds=2)
        p300.drop_tip()
        for well, tip, s, side in zip(magsamps, mixTips, src, sides):
            p300.pick_up_tip(tip)
            well_mix(mtimes, well, 180, side)
            p300.blow_out()
            p300.aspirate(10, well.top(-3))
            p300.return_tip()
        magdeck.engage(height=magheight)
        protocol.comment('Incubating on MagDeck for 4 minutes.')
        protocol.delay(minutes=4)#CHANGED FOR WATER RUN
        protocol.comment(f'Removing supernatant from Wash {msg}:')
        for well, tip, side in zip(magsamps, mixTips, sides):
            p300.pick_up_tip(tip)
            supernatant_removal(420, well, wasteLoc, side) #**changed from 520 to 420**
            p300.return_tip()
        magdeck.disengage()
    wash_step(wb1, 20, waste1, '1 VHB Buffer 400uL')
    wash_step(wb2, 10, waste1, '2 SPM Buffer 400uL')
    wash_step(ethanol1, 10, waste2, '3 SPM Buffer again 400uL')
    #wash_step(ethanol2, 10, waste2, '4 Ethanol 2') *omega biotek doesn't require this wash step*
    magdeck.engage (height=magheight)
    protocol.comment('Allowing beads to air dry for 1 minutes.')
    protocol.delay(minutes=1) #NOT CHANGED FOR WATER RUN
    p300.flow_rate.aspirate = 10 #changed from 20
    protocol.comment('Removing any excess ethanol from wells:')
    for well, tip, side in zip(magsamps, mixTips, sides):
        p300.pick_up_tip(tip)
        s = side*-0.5
        p300.transfer(
            180, well.bottom().move(types.Point(x=s, y=0, z=0.4)),
            waste2, new_tip='never')
        p300.return_tip()
    p300.flow_rate.aspirate = 20 #changed from 50
    protocol.comment('Allowing beads to air dry for 2 minutes.')
    protocol.comment('Hi! You are going to start the FIRST ELUTION, ADD HOT EB in RES 1 well 12!')
    protocol.delay(minutes=2) # NOT CHANGED FOR WATER RUN
    magdeck.disengage()
   
    #First elution
    protocol.comment('Adding Elution Buffer to wells for elution 1 of 60uL:')
    for well, side in zip(magsamps, sides):
        p300.pick_up_tip()
        p300.aspirate(20, water.top())
        p300.aspirate(60, water)
        for _ in range(15):
            p300.dispense(
                40, well.bottom().move(types.Point(x=side, y=0, z=2)))
            p300.aspirate(
                40, well.bottom().move(types.Point(x=side, y=0, z=0.5)))
        p300.dispense(70, well)
        p300.blow_out()
        _drop_tip()
    protocol.comment('Incubating at room temp for 15 minutes.')
    protocol.delay(minutes=15)  #CHANGED FOR WATER RUN
    # Step 21 - Transfer elutes to clean plate
    magdeck.engage(height=magheight)
    protocol.comment('Incubating on MagDeck for 2 minutes.')
    protocol.delay(minutes=2) # NOT CHANGED FOR WATER RUN
    protocol.comment('Transferring 60 uL of elution1 to final plate:') #E1 should be 60 uL
    p300.flow_rate.aspirate = 10
    for src, dest, side in zip(magsamps, elutes, sides):
        p300.pick_up_tip()
        p300.flow_rate.aspirate = 20
        p300.aspirate(60, src.bottom().move(types.Point(x=-side, y=0, z=0.6)))
        p300.dispense(60, dest)
        p300.aspirate(10, dest.top(-3))
        _drop_tip()
    magdeck.disengage()
    protocol.comment('Hi! You are going to start the SECOND ELUTION, ADD MORE HOT EB AND add new clean plate in SLOT 2!')
    protocol.delay(minutes=3) # NOT CHANGED FOR WATER RUN
# step 22 - second elution
    protocol.comment('SECOND ELUTION: Adding 40 UL Elution Buffer to wells')
    p300.pick_up_tip()  
    for well, s in zip(magsamps, sides):
            p300.flow_rate.aspirate = 70
            p300.aspirate(20, water.top())
            p300.aspirate(30, water)
            p300.dispense(50, well.top(+1))
            p300.aspirate(10, well.top(+1))
    p300.blow_out()
    p300.drop_tip()
#     mix water of second elution with sample
    protocol.comment('Mixing for second elution')
    for well, tip, side in zip(magsamps, mixTips, sides):
            _pick_tip()
            p300.aspirate(20, well.bottom().move(types.Point(x=side, y=0, z=0.5)))
            for _ in range (15):
                p300.dispense(20, well.bottom().move(types.Point(x=side, y=0, z=2)))
                p300.aspirate(20, well.bottom().move(types.Point(x=side, y=0, z=0.5)))
            p300.dispense(30, well)
            p300.blow_out()
            p300.return_tip()
    protocol.comment('Incubating at room temp for 15 minutes.')
    protocol.delay(minutes=15) #CHANGED FOR WATER RUN
   
#     Step 23 - Transfer elutes to a second clean plate
    magdeck.engage(height=magheight)
    protocol.comment('Incubating on MagDeck for 2 minutes.')
    protocol.delay(minutes=2) # NOT CHANGED FOR WATER RUN
 
    protocol.comment('Transferring 40 uL of second elution to final plate:')
    p300.flow_rate.aspirate = 10 #changed from 20
    for src, tip, dest, side in zip(magsamps, mixTips, elutes2, sides):
        _pick_tip()
        p300.aspirate(40, src.bottom().move(types.Point(x=-side, y=0, z=0.6)))
        p300.dispense(40, dest)
        p300.drop_tip()
     
    magdeck.disengage()
    light = protocol.set_rail_lights(False)
    protocol.comment('Congratulations!')