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

# System modules
from flask_restx import Namespace, Resource, fields
from astropy.time import Time

# Custom modules
import devices
from config import constants

api = Namespace('camera', description='Camera related operations')

    
@api.route("/frame/binning")
class FrameBinning(Resource):
    """Binning of the camera."""

    def get(self):
        """Retrieve the binning of the camera."""
        return devices.cam.binning

    def put(self):
        """Set a new binning for the camera."""
        binning = api.payload
        devices.cam.binning = binning
        return devices.cam.binning


@api.route("/cooler")
class Cooler(Resource):
    """Manage the CCD cooler status"""

    @api.response(200, 'Success', fields.Boolean())
    def get(self):
        """Check wether the CCD cooler is on or off."""
        return devices.cam.cooler

    @api.response(200, 'Success', fields.Boolean())
    def put(self):
        """Set on or off the CCD cooler."""
        state = api.payload
        devices.cam.cooler = state
        return devices.cam.cooler

    
@api.route("/cooler/temperature")
class CoolerTemperature(Resource):
    """Info on the cooler temperature"""

    @api.response(200, 'Success', fields.Float())
    def get(self):
        """Retrieve the CCD cooler temperature."""
        return devices.cam.temperature


@api.route("/cooler/temperature/setpoint")
class CoolerTemperatureSetpoint(Resource):
    """Manage the CCD temperature"""

    @api.response(200, 'Success', fields.Float())
    def get(self):
        """Retrieve the temperature of the CCD."""
        return devices.cam.setpoint

    @api.response(200, 'Success', fields.Float())
    def put(self):
        """Set a new temperature of the CCD."""
        state = api.payload
        devices.cam.temperature = state
        return devices.cam.setpoint

    
@api.route("/filters")
class Filter(Resource):
    """Camera filters names."""

    def get(self):
        """Retrieve the filter names."""
        return constants.filter_number

    
@api.route("/filter")
class Filter(Resource):
    """Camera filter information."""

    def get(self):
        """Retrieve the current filter."""
        res = devices.cam.filter
        err = devices.cam.error
        return res if not err else {"Error": str(err)}

    
@api.route("/filter/movement")
class FilterMovement(Resource):
    """Manage the camera filter wheel."""

    @api.response(200, 'Success', fields.Boolean())
    def get(self):
        """Check if the filter wheel is moving."""
        return devices.cam.is_moving

    @api.response(200, 'Success', fields.Float())
    def post(self):
        """Set a new filter."""
        target = api.payload
        devices.cam.filter = target
        return devices.cam.filter

    
@api.route("/frame")
class Frame(Resource):
    """Camera frame information."""

    def get(self):
        """Retrieve the current frame."""
        frame = {
            "xrange": devices.cam.xrange,
            "yrange": devices.cam.yrange,
            "binning": devices.cam.binning,
            "maxrange": devices.cam.max_range,
        }
        return frame

    
@api.route("/frame/custom")
class FrameCustom(Resource):
    """Camera custom frame."""

    def put(self):
        """Set a custom windowing."""
        new_frame = api.payload
        devices.cam.binning = new_frame["binning"]
        frame = {
            "xrange": new_frame["xrange"],
            "yrange": new_frame["yrange"],
            "binning": new_frame["binning"]
        }        
        return frame

    
@api.route("/frame/full")
class FrameFull(Resource):
    """Camera full frame."""

    def put(self):
        """Set the ccd to full frame in current binning."""
        return devices.cam.full_frame()

    
@api.route("/frame/half")
class FrameHalf(Resource):
    """Camera frame of half size the full frame."""

    def put(self):
        """Set a center ccd window spanning half the 
        size of the full frame in the current binning."""
        return devices.cam.half_frame()

    
@api.route("/frame/small")
class FrameSmall(Resource):
    """Camera frame of 2 arcmin."""

    def put(self):
        """Set a center ccd window spanning 2 arcminutes 
        on the sky."""
        return devices.cam.small_frame()

    
@api.route("/frame/temperature")
class FrameTemperature(Resource):
    """Ambient temperature."""

    def get(self):
        """Retrieve the ambient temperature"""
        return devices.cam.ambient

    
@api.route("/snapshot/")
class Snapshot(Resource):
    """The acquired image."""

    def get(self):
        """Get the acquired image."""
        return devices.cam.download()

    
@api.route("/snapshot/acquisition")
class SnapshotAcquisition(Resource):
    """Manage the acquisition of an image."""

    def get(self):
        """Retrieve the status of the acquisition process."""
        return devices.cam.state

    def post(self):
        """Start a new acquisition."""
        new = api.payload # exptime, type
        gps = Time(devices.ast.utc, format="unix")
        return devices.cam.start(new["exptime"],
                               new["type"],
                               gps)

    def delete(self):
        """Retrieve the status of the acquisition process."""
        return devices.cam.abort()
    

@api.route("/cooler/warmup")
class CoolerTemperatureSetpoint(Resource):
    """Manage the warmup of the CCD."""

    def post(self):
        """Start the warm up the CCD."""
        pass

    def delete(self):
        """Stop the warm up of the CCD."""
        pass

    
@api.route("/power")
class Power(Resource):
    """Manage the CCD camera power using the external switch"""

    @api.response(200, 'Success', fields.Boolean())
    def get(self):
        """Check if the camera is on or off."""
        return devices.sof.state

    @api.response(200, 'Success', fields.Boolean())
    def put(self):
        """Switch on or off the camera"""
        target = api.payload
        devices.sof.state = target
        return devices.sof.state

    
@api.route("/power/cycle")
class PowerCycle(Resource):
    """Manage the CCD camera reboot."""

    def post(self):
        """Reboot the camera."""
        return devices.sof.reboot()
