import abc
from typing import BinaryIO, Protocol, Optional, Union, List, Dict, Tuple, Generator

from .diagrams import GraphMachine, HierarchicalGraphMachine
from ..core import ModelState


class GraphProtocol(Protocol):

    def draw(self, filename: Optional[Union[str, BinaryIO]], format:Optional[str] = ...,
             prog: Optional[str] = ..., args:str = ...) -> Optional[str]: ...

class GraphModelProtocol(Protocol):

    def get_graph(self, title: Optional[str]=None, force_new: bool=False, show_roi: bool=False) -> GraphProtocol: ...


class BaseGraph(metaclass=abc.ABCMeta):
    machine: Union[GraphMachine, HierarchicalGraphMachine]
    fsm_graph: Optional[GraphProtocol]
    def __init__(self, machine: GraphMachine) -> None: ...
    @abc.abstractmethod
    def generate(self) -> None: ...
    @abc.abstractmethod
    def set_previous_transition(self, src: str, dst: str) -> None: ...
    @abc.abstractmethod
    def reset_styling(self) -> None: ...
    @abc.abstractmethod
    def set_node_style(self, state: ModelState, style: str) -> None: ...
    @abc.abstractmethod
    def get_graph(self, title: Optional[str] = ..., roi_state: Optional[str] = ...) -> GraphProtocol: ...
    def _convert_state_attributes(self, state: Dict[str, str]) -> str: ...
    def _get_state_names(self, state: ModelState) -> Generator[str, None, None]: ...
    def _transition_label(self, tran: Dict[str, str]) -> str: ...
    def _get_global_name(self, path: List[str]) -> str: ...
    def _get_elements(self) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]: ...
    def _flatten(self, *lists: Union[str, Tuple[str]]) -> List[str]: ...
