#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Part of the PsychoPy library
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2022 Open Science Tools Ltd.
# Distributed under the terms of the GNU General Public License (GPL).
# Contributor: maqadri - mqadri@holycross.edu

"""
    Interface to Phidgets for analog input, digital input, digital output (5V), and relay control.
"""
from psychopy.experiment.components import BaseComponent, Param, getInitVals
#Modeled after qmix/pump

from pathlib import Path

class PhidgetRelayComponent(BaseComponent):
    """Operate a Phidget Relay (0/0/4) or (0/0/8)"""
    # mark it as coming from this plugin
    plugin = "psychopy-phidgets"
    # specify what libraries it has code for - PsychoPy and/or PsychoJS
    targets = ["PsychoPy"]
    # specify what category (or categories) to list this Component under in Builder
    categories = ['I/O']
    # path to this Component's icon file - ignoring the light/dark/classic folder and any @2x in the filename (PsychoPy will add these accordingly)
    iconFile = Path(__file__).parent / 'phidgets.png'
    # Text to display when this Component is hovered over
    tooltip = 'Phidget: control operant chamber events using (a) relay(s)'
    # what is the earliest version of PsychoPy this Component works with?
    version = "2025.1.1"
    # is this Component still in beta?
    beta = True


    def __init__(self, exp, parentName, name='phidgetRelay',
                 startType='time (s)', startVal=0.0,
                 stopType='duration (s)', stopVal=3.0,
                 startEstim='', durationEstim='',
                 channelList='',
                 serialNumber='',
                 reversedRelay=False,
                 syncToScreen=True):

        super(PhidgetRelayComponent, self).__init__(
            exp, parentName, name,
            startType=startType, startVal=startVal,
            stopType=stopType, stopVal=stopVal,
            startEstim=startEstim, durationEstim=durationEstim)

        self.type = 'PhidgetRelay'
        self.url = 'https://www.psychopy.org/builder/components/phidget.html'

        #print('Try Import')
        self.exp.requireImport(importName='PhidgetOutputComponent',
                               importFrom='psychopy.hardware')

        # Order in which the user-settable parameters will be displayed
        # in the component's properties window.
        self.order += ['syncToScreen',  # Basic tab
                        'channelList', 'serialNumber', 'reversedRelay', # Hardware tab
                      ]

        self.params['channelList'] = Param(
            channelList, categ='Hardware',
            valType='list', inputType="single",
            hint='The list of channels controlled by this component',
            label='channelList')

        self.params['serialNumber'] = Param(
            serialNumber, categ='Hardware',
            valType='num', inputType="int",
            hint='Serial number for your Phidget Output relay (leave empty if only one Phidget attached to PC)',
            label='serialNumber')

        self.params['reversedRelay'] = Param(
            reversedRelay, categ='Hardware',
            valType='bool', inputType="bool", allowedVals=[True, False],
            hint='Set reversed if you want the relay to start on and turn off for the indicated duration',
            label='reversedRelay')

        self.params['syncToScreen'] = Param(
            syncToScreen, valType='bool', inputType="bool", categ='Basic',
            allowedVals=[True, False],
            hint='Sync relay events to the screen refresh',
            label='syncToScreen')

    def writeRunOnceInitCode(self, buff):
        code = ('# Initialize relays\n'
                '%(name)s = PhidgetOutputComponent(channelList = %(channelList)s, '
                                                           'serialNumber = %(serialNumber)s, '
                                                           'reversedRelay = %(reversedRelay)s)\n'
                % self.params )
        buff.writeOnceIndentedLines(code)

    def writeRoutineStartCode(self, buff):
        """Write the code that will be called at the start of the routine.
        """

        code = ('\n'
                '%(name)s.openRelay()\n'
                % self.params)

        buff.writeIndentedLines(code)

    def writeFrameCode(self, buff):
        """Write the code that will be called every frame.
        """


        buff.writeIndented("# *%s* updates\n" % (self.params['name']))
        self.writeStartTestCode(buff)
        buff.writeIndented("%(name)s.status = STARTED\n" % self.params)

        if self.params['syncToScreen'].val:
            code = ('\n'
                    'win.callOnFlip(%(name)s.closeRelay)\n'
                    % self.params)
        else:
            code = ('\n'
                    '%(name)s.closeRelay()\n'
                    % self.params)

        buff.writeIndentedLines(code)
        buff.setIndentLevel(-1, relative=True)

        # Test for stop (only if there was some setting for duration or
        # stop).
        if self.params['stopVal'].val not in ['', None, -1, 'None']:
            self.writeStopTestCode(buff)
            buff.writeIndented("%(name)s.status = FINISHED\n" % self.params)

            if self.params['syncToScreen'].val:
                code = ('\n'
                        'win.callOnFlip(%(name)s.openRelay)\n'
                        % self.params)
            else:
                code = ('\n'
                        '%(name)s.openRelay()\n'
                        % self.params)

            buff.writeIndentedLines(code)
            buff.setIndentLevel(-2, relative=True)


    def writeRoutineEndCode(self, buff):
        #Leave the relay in the default state
        code = ('\n'
                '%(name)s.openRelay()\n'
                % self.params)

        buff.writeIndentedLines(code)

        # get parent to write code too (e.g. store onset/offset times)
        super().writeRoutineEndCode(buff)

    def writeExperimentEndCode(self, buff):
        #Leave the relay in the default state
        code = ('\n'
                '%(name)s.openRelay()\n'
                % self.params)

        buff.writeIndentedLines(code)

        # get parent to write code too (e.g. store onset/offset times)
        super().writeExperimentEndCode(buff)