import { Note } from "./Note";
import log from "loglevel";

/**
 * A note head with shape and fill information belonging to a [[Note]].
 */
export class Notehead {
    /**
     * @param sourceNote
     * @param shapeTypeXml The shape type given from XML.
     *                     See https://usermanuals.musicxml.com/MusicXML/Content/ST-MusicXML-notehead-value.htm
     * @param filledXml The XML flag to fill the note shape. Can be undefined if not included in XML.
     *                  If undefined, the filled parameter will be calculated by note duration (d < half note => filled)
     */
    constructor(sourceNote: Note, shapeTypeXml: string, filledXml: boolean = undefined) {
        this.sourceNote = sourceNote;
        this.setShapeFromXml(shapeTypeXml, filledXml);
    }

    /** shape of the note head (normal, square, triangle, etc.) */
    private shape: NoteHeadShape;
    private filled: boolean;
    /** the [[Note]] this NoteHead belongs to. */
    private sourceNote: Note;
    // note that color is stored in the sourceNote, because note.Notehead is undefined for normal noteheads.

    /** Sets the note head's shape from XML parameters.
     * @param shapeTypeXml The XML shape.
     * @param filledXmlAttribute the filled parameter as given in XML.
     *                           Can be undefined if not given in XML or if it should be calculated from note duration.
     *                           If undefined, this.sourceNote should not be undefined.
     */
    public setShapeFromXml(shapeTypeXml: string, filledXmlAttribute: boolean = undefined): void {
        this.shape = Notehead.ShapeTypeXmlToShape(shapeTypeXml);

        let filled: boolean = filledXmlAttribute;
        if (filled === undefined) { // don't replace undefined check
            if (!this.sourceNote) {
                // this should not happen. Either filledXmlAttribute or sourceNote should be defined.
                log.warn("notehead: sourceNote and filledXmlAttribute undefined.");
                filled = true;
            } else {
                filled = this.sourceNote.Length.Denominator > 2;
            }
        }
        this.filled = filled;
    }

    public get SourceNote(): Note {
        return this.sourceNote;
    }

    public get Shape(): NoteHeadShape {
        return this.shape;
    }
    public get Filled(): boolean {
        return this.filled;
    }

    /** Converts xml attribute to NoteHeadShape.
     * Necessary because "circle-x" is not a valid enum member name.
     */
    public static ShapeTypeXmlToShape(shapeTypeXml: string): NoteHeadShape {
        switch (shapeTypeXml.toLowerCase()) {
            case "normal":
                return NoteHeadShape.NORMAL;
            case "x":
                return NoteHeadShape.X;
            case "slash":
                return NoteHeadShape.SLASH;
            case "diamond":
                return NoteHeadShape.DIAMOND;
            case "square":
                return NoteHeadShape.SQUARE;
            case "la": // Musescore displays this as a square
                return NoteHeadShape.SQUARE;
            case "do":
            case "triangle":
                return NoteHeadShape.TRIANGLE;
            case "rectangle":
                return NoteHeadShape.RECTANGLE;
            case "circle-x":
                return NoteHeadShape.CIRCLEX;
            default:
                log.info("unsupported/unhandled xml notehead '" + shapeTypeXml + "'. Using normal notehead.");
                return NoteHeadShape.NORMAL;
        }
    }
}

/** shape of a note head, needs to be supported by MusicXML and Vexflow. */
export enum NoteHeadShape {
    CIRCLEX,
    DIAMOND,
    NORMAL,
    RECTANGLE,
    SLASH,
    SQUARE,
    TRIANGLE,
    X,
    // TODO: Add the rest from https://usermanuals.musicxml.com/MusicXML/Content/ST-MusicXML-notehead-value.htm
    // currently all Vexflow supported shapes present
}
