#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net )

This file is part of the Laborejo Software Suite ( https://www.laborejo.org ),

Laborejo2 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.

This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import logging; logger = logging.getLogger(__name__); logger.info("import")

#Standard Library Modules

#Third Party Modules

#Template Modules
import template.engine.pitch as pitch
import template.engine.duration as duration

#Our modules
class Cursor:
    """There is only one cursor in the program.
    Each track has its own state with its own gap, tickindex etc.
    but the cursor is unique.
    Used for pitch and states which apply to all tracks, like
    "insert next note with dot?"

    The cursor moves 'on stafflines' not through the keysig. Adaption to the keysig is done
    by the api like in insertCursorCode or insertKeysignature
    """
    def __init__(self, score):
        self.score = score
        self.pitchindex = pitch.ly2pitch["c'"]
        self.prevailingBaseDuration = duration.D4
        self.persistentPrevailingDot = False #For the sake of simplicity this is only a bool. No "two prevailing dots"
        self.oneTimePrevailingDotInverter = False #effects persistentPrevailingDot

    def up(self):
        """Move the cursor/pitchindex up, +50.
        The cursor always goes up and down the c major scale.
        Call with Cursor.up(). Class method """
        self.pitchindex += pitch.STEP
        self.correctPitchindex()

    def down(self):
        """Move the cursor/pitchindex down, -50.
        The cursor always goes up and down the c major scale.
        Call with Cursor.down().  Class method"""
        self.pitchindex -= pitch.STEP
        self.correctPitchindex()

    def upOctave(self):
        """Move the cursor/pitchindex up, +350.
        Call with Cursor.upOctave().  Class method"""
        self.pitchindex += pitch.OCTAVE
        self.correctPitchindex()

    def downOctave(self):
        """Move the cursor/pitchindex down, -350.
        Call with Cursor.downOctave().  Class method"""
        self.pitchindex -= pitch.OCTAVE
        self.correctPitchindex()

    def correctPitchindex(self):
        if self.pitchindex >= pitch.MAX:
            self.pitchindex = pitch.MAX
        elif self.pitchindex <= pitch.MIN:
            self.pitchindex = pitch.MIN
        else:
            self.pitchindex = pitch.toWhite[self.pitchindex]

    def getPrevailingDot(self):
        """0 or 1.
        Also toggles oneTimePrevailingDotInverter"""
        if self.persistentPrevailingDot:
            if self.oneTimePrevailingDotInverter:
                self.oneTimePrevailingDotInverter = not self.oneTimePrevailingDotInverter
                return 0
            else:
                return 1
        else:
            if self.oneTimePrevailingDotInverter:
                self.oneTimePrevailingDotInverter = not self.oneTimePrevailingDotInverter
                return 1
            else:
                return 0

    def distanceInDiatonicStepsFromTrebleB(self):
        return pitch.distanceInDiatonicSteps(pitch.ly2pitch["b'"], self.pitchindex) #offset from the middle line in treble clef h', which is 0. c'' is -1, a' is +1

    def asDotOnLine(self, clef):
        return self.distanceInDiatonicStepsFromTrebleB() + clef.asDotOnLineOffset

    def exportObject(self, trackState):
        """Every time the cursor moves this will be called.

        return a dict which is a good layout
        export basis. For example for GUI frontends. They don't have to
        parse and calculate their own values in slow pure Python then.

        This is for GUIs etc.  not for saving to JSOn. The cursor is not
        saved.
        """
        tempoItem = trackState.track.parentData.tempoTrack.tempoAtTickPosition(trackState.tickindex) #TODO: maybe get that from a cached version.
        item = trackState.track.currentItem()
        block = trackState.track.currentBlock()

        return {
            "type": "Cursor",
            "trackIndex": trackState.index(),
            "track" : trackState.track,
            "cboxMidiOutUuid" : trackState.track.sequencerInterface.cboxMidiOutUuid, #used for midi throught. Step midi shall produce sound through the current track.
            "midiChannel" : trackState.midiChannel(), #zero based
            "trackId" : id(trackState.track),
            "position" : trackState.position(),
            "tickindex" : trackState.tickindex,
            "dotOnLine": self.asDotOnLine(trackState.clef()),
            "pitch" : self.pitchindex,
            "lilypondPitch" : pitch.pitch2ly[self.pitchindex],
            "appending" : trackState.isAppending(),
            "blockindex" : trackState.blockindex,
            "block" : block,
            "localCursorIndex" : block.localCursorIndex,
            "itemId" : id(item),
            "item" : item,
            "tempoUnitsPerMinute" : tempoItem.unitsPerMinute,
            "tempoReferenceTicks" : tempoItem.referenceTicks,
            "tempoGraphType" : tempoItem.graphType,
        }
