use text_editing::TextLine;

/// Represents from which type of element to which type of element an arrow should be drawn.
pub enum ArrowKind {
    /// An arrow from a place to a transition.
    PlaceToTransition,
    /// An arrow from a place to a placeplace.
    TransitionToPlace,
    /// An arrow from a place to a point.
    PlaceToPoint,
    /// An arrow from a point to a place.
    PointToPlace,
    /// An arrow from a transition to a point.
    TransitionToPoint,
    /// An arrow from a point to a transition.
    PointToTransition,
}

/// The renderer trait is used to display the elements of the petri net in a specific way.
/// Every drawing method starts with `draw_` and takes the `context` as t he first argument.
/// The positions are always given relative to the center without zoom applied.
/// Zoom has to be applied by the renderer.
pub trait Renderer {
    /// Renders some indications if simulation mode is enabled.
    fn draw_simulated(&mut self, simulated: bool);

    /// This draws a place of the petri net.
    ///
    /// * `pos`: The center of the place.
    /// * `radius`: The radius of the place.
    /// * `zoom`: The zoom used for rendering.
    /// * `name`: The name of the place as char array.
    /// * `name_cursor`: The position of the cursor inside the name.
    /// * `show_cursor`: Indicates if the cursor is shown for this place.
    /// * `count`:
    ///     The token count of the place.
    ///     A different visualization is recommended if it contains at least one token.
    /// * `selected`: Indicates if the place is currently selected.
    fn draw_place(
        &mut self,
        pos: [f32; 2],
        radius: f32,
        zoom: f32,
        name: &TextLine,
        name_cursor: usize,
        show_cursor: bool,
        count: usize,
        selected: bool,
    );

    /// This draws a transition of the petri net.
    ///
    /// * `pos`: The center of the transition.
    /// * `width`: The width of the transition.
    /// * `height`: The height of the transition.
    /// * `zoom`: The zoom used for rendering.
    /// * `name`: The name of the transition as char array.
    /// * `name_cursor`: The position of the cursor inside the name.
    /// * `show_cursor`: Indicates if the cursor is shown for this transition.
    /// * `selected`: Indicates if the transition is currently selected.
    /// * `forward`: Indicates if the transition can fire.
    /// * `backwards`: Indicates if the transition can fire backwards.
    fn draw_transition(
        &mut self,
        pos: [f32; 2],
        width: f32,
        height: f32,
        zoom: f32,
        name: &TextLine,
        name_cursor: usize,
        show_cursor: bool,
        selected: bool,
        forward: bool,
        backwards: bool,
    );

    /// This draws a transition frame around a set of transitions.
    ///
    /// * `left`: The left bounds of the frame.
    /// * `right`: The left bounds of the frame.
    /// * `top`: The left bounds of the frame.
    /// * `bottom`: The left bounds of the frame.
    /// * `zoom`: The zoom used for rendering.
    /// * `name`: The name of the frame.
    fn draw_transition_frame(
        &mut self,
        left: f32,
        right: f32,
        top: f32,
        bottom: f32,
        zoom: f32,
        name: &str,
    );

    /// This draws a line from position `from` to position `to`.
    /// Lines are used for visualizing nodes with multiple instances.
    fn draw_line(&mut self, from: [f32; 2], to: [f32; 2], zoom: f32);

    /// This draws an arrow from an element at position `from` to an element at position `to`.
    /// An element is either a place, a transition or a point.
    /// Both elements are of a different type. The element types are specified by `arrow_kind`.
    /// Depending on the element type, there might need to be different offsets or different curvatures.
    fn draw_arrow(
        &mut self,
        from: [f32; 2],
        to: [f32; 2],
        radius: f32,
        width: f32,
        height: f32,
        zoom: f32,
        arrow_kind: ArrowKind,
    );

    /// This draws a global input text field. The position is not further specified, so it can be anywhere.
    ///
    /// * `text`: The text in the field.
    /// * `cursor`: The position of the cursor inside the text.
    fn draw_field(&mut self, text: &TextLine, cursor: usize);

    /// This draws a box for when the user selects multiple objects using a box.
    /// `corner1` and `corner2` are the positions of two opposite corners of the box.
    fn draw_select_box(&mut self, corner1: [f32; 2], corner2: [f32; 2], zoom: f32);

    /// This draws a text box, which might contains multiple lines of text.
    ///
    /// * `text`: The text as a list of lines, which are each represented as a list of lines.
    /// * `cursor`: The cursor position on the specified line.
    /// * `line`: The line, where the cursor currently is.
    /// * `offset`: Indicates by how many lines the text is moved up.
    fn draw_text_box(&mut self, text: &Vec<TextLine>, cursor: usize, line: usize, offset: usize);

    /// Finishes rendering of a single frame.
    fn finish(&mut self);
}
