"""
Example of a basic midas frontend that has one "manually triggered" equipment.

You can trigger event readout by going to the URL ?cmd=Trigger/MyManualEquipment
(e.g. http://localhost:8080?cmd=Trigger/MyManualEquipment).

You can also trigger from another python client using code like:

```
import midas.client
other_client_name = "myfe_manual"
other_event_id = 567

with midas.client.MidasClient("my_client") as client:
    conn = client.connect_to_other_client(other_client_name)
    client.manual_trig_client_call(conn, other_event_id)
    client.disconnect_from_other_client(conn)
```


In this example, we set the equipment type as `midas.EQ_MANUAL_TRIG`. You could also
merge it with other types, such as `midas.EQ_MANUAL_TRIG|midas.EQ_POLLED`. In that case,
an event would be readout when either `poll_event()` returns True OR when it is
manually triggered.
"""

import midas
import midas.frontend
import midas.event

class MyManualEquipment(midas.frontend.EquipmentBase):
    """
    We define an "equipment" for each logically distinct task that this frontend
    performs. For example, you may have one equipment for reading data from a
    device and sending it to a midas buffer, and another equipment that updates
    summary statistics every 10s.
    
    Each equipment class you define should inherit from 
    `midas.frontend.EquipmentBase`, and should define a `readout_func` function.
    If you're creating a "polled" equipment (rather than a periodic one), you
    should also define a `poll_func` function in addition to `readout_func`.
    """
    def __init__(self, client):
        # The name of our equipment. This name will be used on the midas status
        # page, and our info will appear in /Equipment/MyManualEquipment in
        # the ODB.
        equip_name = "MyManualEquipment"
        
        # Define the "common" settings of a frontend. These will appear in
        # /Equipment/MyManualEquipment/Common. The values you set here are
        # only used the very first time this frontend/equipment runs; after 
        # that the ODB settings are used.
        default_common = midas.frontend.InitialEquipmentCommon()
        default_common.equip_type = midas.EQ_MANUAL_TRIG
        default_common.buffer_name = "SYSTEM"
        default_common.trigger_mask = 0
        default_common.event_id = 567
        default_common.period_ms = 100
        default_common.read_when = midas.RO_RUNNING
        default_common.log_history = 0
        
        # You MUST call midas.frontend.EquipmentBase.__init__ in your equipment's __init__ method!
        midas.frontend.EquipmentBase.__init__(self, client, equip_name, default_common)
        
        # You can set the status of the equipment (appears in the midas status page)
        self.set_status("Initialized")
        
    def readout_func(self):
        """
        For a periodic equipment, this function will be called periodically
        (every 100ms in this case). It should return either a `midas.event.Event`
        or None (if we shouldn't write an event).
        """
        
        # In this example, we just make a simple event with one bank.
        event = midas.event.Event()

        # This flag says whether this was a manual trigger or not. You can use it
        # for any purpose. In our case, we set a bit in the event's trigger mask
        # (which is a 16-bit number).
        if self.is_manual_trig:
            event.header.trigger_mask |= 0x8000
        
        # Create a bank (called "MYBK") which in this case will store 8 ints.
        # data can be a list, a tuple or a numpy array.
        # If performance is a strong factor (and you have large bank sizes), 
        # you should use a numpy array instead of raw python lists. In
        # that case you would have `data = numpy.ndarray(8, numpy.int32)`
        # and then fill the ndarray as desired. The correct numpy data type
        # for each midas TID_xxx type is shown in the `midas.tid_np_formats`
        # dict.
        data = [1,2,3,4,5,6,7,8]
        event.create_bank("MYBK", midas.TID_INT, data)
        
        return event

class MyFrontend(midas.frontend.FrontendBase):
    """
    A frontend contains a collection of equipment.
    You can access self.client to access the ODB etc (see `midas.client.MidasClient`).
    """
    def __init__(self):
        # You must call __init__ from the base class.
        midas.frontend.FrontendBase.__init__(self, "myfe_manual")
        
        # You can add equipment at any time before you call `run()`, but doing
        # it in __init__() seems logical.
        self.add_equipment(MyManualEquipment(self.client))
        
    def begin_of_run(self, run_number):
        """
        This function will be called at the beginning of the run.
        You don't have to define it, but you probably should.
        You can access individual equipment classes through the `self.equipment`
        dict if needed.
        """
        self.set_all_equipment_status("Running", "greenLight")
        self.client.msg("Frontend has seen start of run number %d" % run_number)
        return midas.status_codes["SUCCESS"]
        
    def end_of_run(self, run_number):
        self.set_all_equipment_status("Finished", "greenLight")
        self.client.msg("Frontend has seen end of run number %d" % run_number)
        return midas.status_codes["SUCCESS"]
    
    def frontend_exit(self):
        """
        Most people won't need to define this function, but you can use
        it for final cleanup if needed.
        """
        print("Goodbye from user code!")
        
if __name__ == "__main__":
    # The main executable is very simple - just create the frontend object,
    # and call run() on it.
    with MyFrontend() as my_fe:
        my_fe.run()