#!/usr/bin/env python3.5
# Copyright 2017 Digital
#
# This file is part of DigiLib.
#
# DigiLib is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DigiLib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DigiLib.  If not, see <http://www.gnu.org/licenses/>.

# Python modules
import logging
import threading
import traceback
# Third party modules
import curio
import digilib.network

class FakeGPIO(object):
    pin_values = {}
    def setup()
    def output(self,pins,value):
        lpin.debug("setting pin(s) {} to value {}".format(
            pins, value
        ))
        if type(pins) == int:
            pins = [pins]
        for p in pins:
            self.pin_values[p] = value
    def read(self,pin):
        return self.pin_values[pin]

try:
    import RPi.GPIO as gpio
    gpio.setmode(gpio.BCM)
except:
    # print("Using FakeGPIO because RPi.GPIO was not found")
    gpio = FakeGPIO()

log = logging.getLogger(__name__+"")
lpin = logging.getLogger(__name__+".pin")

class PinBase(object):
    """PinBase is the base class for all classes representing a gpio pin"""
    pin_number = None
    value = None
    def __init__(self,pin_number):
        super(PinBase,self).__init__()
        self.pin_number = pin_number
        self.value = self.value_low
    def output(self,value):
        lpin.info(
            "pin {} set to {}".format(
                str(self.pin_number),
                str(value)
            )
        )
        self.value = value
        gpio.output(self.pin_number,value)
    def read(self):
        value = gpio.output(self.pin_number,value)
        lpin.debug(
            "pin {} has value {}".format(
                str(self.pin_number),
                str(value)
            )
        )
        return value

class DigitalPin(PinBase):
    value_high = True
    value_low = False
    def __init__(self,pin_number):
        super(DigitalPin,self).__init__(pin_number)

class AnalogPin(PinBase):
    value_high = 1
    value_low = 0
    def __init__(self,pin_number):
        super(AnalogPin,self).__init__()

class PinControllerBase(object):
    """docstring for PinControllerBase.
    PinControllerBase is the base class for all classes controlling one or more physical devices connected to a gpio header

    """
    pins = []
    def __init__(self):
        super(PinControllerBase, self).__init__()
    def make_digital_pin(self,*args):
        return DigitalPin(*args)
    def make_analog_pin(self,*args):
        return AnalogPin(*args)

class PinAPIBase(object):
    """docstring for PinAPI.
    PinAPIBase is the base class for all classes providing an api to multiple
    PinController.
    """
    controllers = []
    def __init__(self):
        super(PinAPIBase, self).__init__()

class PCEngine(PinControllerBase):
    """Test Class"""
    max_speed=1
    speed = 0
    turn_on_speed = 1
    is_on = False
    def __init__(self,pin_on_off,pin_analog):
        super(PCEngine, self).__init__()
        self.pin_on_off = self.make_digital_pin(pin_on_off)
        self.pin_analog = self.make_digital_pin(pin_analog)
        self.pins.append(self.pin_on_off)
        self.pins.append(self.pin_analog)
    def set_speed(self,speed):
        self.pin_analog.output(speed)
        self.speed = speed
    def set_state(self,state):
        """state is boolean and specifies if the engine should be turned on (True) or turned off (False) """
        if state == self.is_on:
            return
        # self.set_speed(speed)
        self.pin_on_off.output(1)
        self.is_on = state

class EnginesController(PinAPIBase):
    engine_left = None
    engine_right = None
    action_in_process = False
    def __init__(self,left,right):
        super(EnginesController,self).__init__()
        self.engine_right = self.make_engine(*right)
        self.engine_left = self.make_engine(*left)
    def __enter__(self):
        if self.action_in_process:
            lpin.debug("action already in process, not entering")
            return False
    def make_engine(self,*args):
        return digilib.pin.PCEngine(*args)
    async def turn(self,direction=None,command=None,respond=None):
        if not direction:
            respond("usage: {} <direction>")
        lpin.debug(threading.current_thread())
        # with self ad
        lpin.info("turning {}".format(direction))
        right_state = self.engine_right.is_on
        right_speed = self.engine_right.speed
        left_state = self.engine_left.is_on
        left_speed = self.engine_left.speed
        if direction == "right":
            self.engine_right.set_state(False)
            self.engine_left.set_state(True)
            self.engine_left.set_speed(1)
        elif direction == "left":
            self.engine_right.set_state(True)
            self.engine_right.set_speed(1)
            self.engine_left.set_state(False)
        await curio.sleep(2)
        # time.sleep(2)
        self.engine_right.set_state(right_state)
        self.engine_right.set_speed(right_speed)
        self.engine_left.set_state(left_state)
        self.engine_left.set_speed(left_speed)
        lpin.info("done turning {}".format(direction))
        # set engines to previous values


class LED(DigitalPin):
    def __init__(self,pin):
        super(DigitalPin,self).__init__(pin)
    def on(self,command=None,respond=None):
        self.output(True)
    def off(self,command=None,respond=None):
        self.output(False)
    def set(self,state=None,command=None,respond=None):
        self.output(state)



if __name__ == "__main__":
    pass






























#