from acqpack import Motor, AsiController, Autosampler, FractionCollector
from acqpack import gui
from acqpack import utils as ut

import yaml
import numpy as np
import pandas as pd

"""
Explanation: SETUP and CALIBRATION
Sampler


Assemble Z-drive, arm, DL needle


Build stand (with desired stage heights)

Loosely attach brackets w/ fasteners to stage bottom
Attach stage (near end of cantilever)
Attach Z-drive assembly
linear guide should be perpendicular to stage surface


Set up controller and software(?), attach cables

Attach deck to stage

Be aware that arm could be obstructed by taller vessels in certain orientations, preventing access to shorter vessels   



HW: adjust hardware limits, alignment with Z axis

HW/DECK: set convenient zero/home corner in config
DECK: Determine transform to HW

Fraction Collector


Assemble slider, arm


subset of Sampler, w/ arm, stage attachment difference
End of explanation
"""


a = Autosampler(Motor('config/motor.yaml'),  AsiController('config/input.yaml'))
gui.stage_control(a)

"""
Explanation: 1 HW: set imits; align XY with Z
physical adjustments
- adjust hall effect stops to maximize range
- make sure:
    - all relevant points on deck are accessible (check with 384-well plate)
    - the stage does not collide with Z-axis (reorientation of the stage/deck may be necessary)
    - at max Z, needle is at or just below top of deck
End of explanation
"""


# in input.yaml, set desired init_dir (x_dir and y_dir)

"""
Explanation: 2 HW/DECK: set convenient XY zero/home corner in config
End of explanation
"""


a = Autosampler(Motor('config/motor.yaml'),  AsiController('config/input.yaml'))
gui.stage_control(a)

# DECK is row; HW is col
# determine XY axes mapping (rotations / reflections)

# determine XYZ offset (i.e. when DECK is 0,0,0, what is HW ?)

# save affine in input_deck.txt

"""
Explanation: 3 DECK: Determine transform to hardware
This is one way to do this; it assumes things are generally rectilinear (90deg rotations) 
Could also do regression between frame1 and frame2 (generalizable way?)

XY rotation / reflection must be re-determined any time:
deck is rotated relative to stage
zero/home corner is changed in config


offset must be re-determined any time:
deck is rotated relative to stage
zero/home corner is changed in config
hall-effect sensors are moved
z-drive and stage are shifted (in any direction) relative to one another
needle is changed to a different one



a x' y' z' w'
x 1. 0. 0. 0.
y 0. 1. 0. 0.
z 0. 0. -1. .0
w 0. 0. 0. 1.
End of explanation
"""


a = Autosampler(Motor('config/motor.yaml'),  AsiController('config/input.yaml'))
a.add_frame('deck', 'config/input_deck.txt')
gui.stage_control(a)

# determine plate 'A01' offset relative to deck origin using above GUI
# i.e. deck coordinates of 'A01'
offset = (2.493, 12.749, 0)

# generate platemap with offset
num_rc = (8,12)   # ct, ct
space_rc = (9,9)  # mm, mm (can do negative if row or column reflected)
platemap = ut.generate_position_table(num_rc, space_rc, offset, True)

# save
filename = '96plate.txt'
platemap

# determine plate 'A01' offset relative to deck origin using above GUI
# i.e. deck coordinates of 'A01'
offset = (8.192, -18.952, 37.700)

# generate platemap with offset
num_rc = (1,4)   # ct, ct
space_rc = (0,28.375)  # mm, mm (can do negative if row or column reflected)
platemap = ut.generate_position_table(num_rc, space_rc, offset, True)

# save
filename = '4scint.txt'
platemap

a.add_frame('plate', 'config/input_deck.txt', 'config/96plate.txt')
a.add_frame('wash', 'config/input_deck.txt', 'config/4scint.txt')

a.goto('plate','name', 'H10')

a.where()

"""
Explanation: 4 PLATES: Make frames in deck coordinates
This is one way to do this; it assumes things are generally rectilinear (90deg rotations) 
Could also do regression between frame1 and frame2 (generalizable way?)
- x,y,z of all well positions are in 'DECK coordinates', i.e. relative to fixed point on deck (ref point, coordinate origin)
- this allows platemaps to be reused so long as:
    - deck is the same
    - position AND orientation of plate on deck is the same
- could also use sequence of transforms (PLATE -> DECK -> HARDWARE), but this is simpler for now
End of explanation
"""


a.goto('deck', 'xyz', (0,0,0))

"""
Explanation: Runtime: option to check deck transform?

be sure to clear deck!!!!!!
go to XY (0,0)
drop Z manually to check (0,)
can:
tweak physically to bring back into alignment 
update deck coordinate frame
End of explanation
"""


from acqpack import Motor, AsiController, Autosampler, FractionCollector
from acqpack import gui
from acqpack import utils as ut

"""
Explanation: Generalized prodcedure to determine transform between two coordinate frames?

regression between set of points from frame1 and frame2

TODO

Determine transforms

TEST

push version



needle


yaml np.array load/store format (better to print to save for readability? or use csv?)

or use RS matrix + offset vector



RUN!
End of explanation
"""


a = Autosampler(Motor('config/motor.yaml'),  AsiController('config/input.yaml'))
gui.stage_control(a)

a.add_frame('plate', 'config/input_deck.txt', 'config/96plate.txt')
a.add_frame('wash', 'config/input_deck.txt', 'config/4scint.txt')

a.goto('plate', 'name', 'A01', zh_travel=35)

a.goto('plate', 'xyz', (0,0,0))

"""
Explanation: Autosampler
End of explanation
"""


f = FractionCollector(AsiController('config/output.yaml'))
gui.stage_control(f)

f.add_frame('plate', 'config/output_deck.txt', 'config/96plate.txt')

f.goto('plate', 'name', 'H12')

f.where('plate')

f.exit()

"""
Explanation: FractionCollector
End of explanation
"""


