#coding: utf-8


#=======================================================================================[ TcycleQUEUE ]=======
class TcycleQUEUE:
  '''Kolejka cykliczna.'''
  _hR=0   									# Głowica czytajaca.
  _hW=0                                                                         # Głowica pisząca.
  _LEN=0									# Długość kolejki.
  _LIST=[]                                                                      # Struktura danych kolejki.

#------------------------------------ INIT -------------------------------------------
#---============================[ __init__ ]==========================================[]
  def __init__(self,L):
    '''Innicjacja z długością kolejki L.'''
    self._LEN=L									# Zapamiętuje długość struktury.
    self._LIST=[None for i in range(L)]						# Tworzy listę zadanej długości.
    self._hR=0									# Ustawia głowicę czytającą na początek listy kolejki.
    self._hW=0									# Ustawia głowicę piszącą na początek listy kolejki.    


#------------------------------------ PREP -------------------------------------------
#---============================[ APPEND ]==========================================[]
  def APPEND(self,I):
    '''Dodaje element na końcu kolejki'''
    self._inc_hW()								# Przesuwa głowicę piszącą.
    self._LIST[self._hW]=I							# Wstawia element w miejsce wskazywane przez głowicę piszącą.

#---============================[ SHIFT ]==========================================[]
  def  SHIFT(self):
    '''Pobiera element ze kolejki. Jeśli jest pusty - zgłasza błąd.'''
    self._inc_hR()								# Przesuwa głowicę czytającą.
    RES=self._LIST[self._hR]							# Pobiera wartość do zwrócenia.
    self._LIST[self._hR]=-RES							# Zaznacza, że pobrano
    return RES           							# Pobiera i zwraca element z pozycji wskazywanej przez głowicę czytajacą.

#---============================[ _inc_hR ]==========================================[]
  def _inc_hR(self):
    '''Jeśli głowica czytająca jest przed końcem listy przesuwa w prawo else zaczyna od zera. 
       Jeśli głowica czytająca wskazuje to samo co głowica pisząca - zgłassza błąd QUEUE is EMPTY.'''
    self.BREAKif_isERROR("-")							# Przerywa jeśli kolejka jest pusta.
    self._hR=(self._hR+1)%self._LEN						# Idzie cyklicznie w prawo.

#---============================[ _inc_hW ]==========================================[]
  def _inc_hW(self):
    '''Jeśli głowica pisząca jest przed końcem listy przesuwa w prawo else zaczyna od zera. 
       Jeśli głowica czytająca wskazuje to samo co głowica pisząca - zgłassza błąd QUEUE is FULL.'''
    oldH=self._hW								# Zapamiętuje pozycję hW.
    self._hW=(self._hW+1)%self._LEN						# Idzie cyklicznie w prawo.
    try:
      self.BREAKif_isERROR("+")							# Przerywa jeśli kolejka jest pełna.
    except Exception as E:                      				# Nastąpił błąd.
      self._hW=oldH								# Przywraca poprzednią pozycję głowicy.			
      raise Exception(f'{E}')							# Zwraca błąd.

#------------------------------------ ERRORS -------------------------------------------
#---============================[ BREAKif_isERROR ]==========================================[]
  def BREAKif_isERROR(self,DIR):
    '''Jeśli DIR="-" i koleja jest pusta zgłasza błąd "QUEUE is EMPTY".'''
    if self._hR!=self._hW:							# Na pewno nie jest pusta ani pełna.
      return									# Kończy.
    # W innym przypadku na pewno jest błąd.
    if DIR=="-":                                                                # EMPTY.
      E='QUEUE is EMPTY'                  					
      print(f'{E}!')
      raise Exception(E)
    if DIR=="+":        							# FULL.
      E='QUEUE is FULL'
      print(f'{E}!')
      raise Exception(E)

#------------------------------------ SHOW -------------------------------------------
#---============================[ SHOW ]==========================================[]
  def SHOW(self):
    '''pokazuje w przyjazny sposób kolejkę.'''
    print('-'*40)
    for i in range(self._LEN):
      I=self._LIST[i]
      if I==None:
        print(f'>"NONE"<',sep=',',end='')
      else:
        print(f'> {I:4d} <',sep=',',end='')
    print()
    for i in range(self._LEN):
      if i==self._hR and i==self._hW:
        print('|^R  W^|',sep='',end='')
      elif i==self._hR:
        print('|^R    |',sep='',end='')
      elif i==self._hW:
        print('|    W^|',sep='',end='')
      else:
        print('|      |',sep='',end='')
    print()
    print('='*40)


#---============================[ __name__ ]==========================================[]
if __name__=="__main__":
  cQUEUE=TcycleQUEUE(5)
  cQUEUE.SHOW()
  for i in range(6):
    try:
      print(f'APPEND({10*i})')
      cQUEUE.APPEND(10*i)
    except Exception as E:
      print(f'ERROR: {E}')
      break
    cQUEUE.SHOW()
  print('.'*100)
  for i in range(24):
    Q='???'
    try:
      Q=cQUEUE.SHIFT()
    except Exception as E:
      print(f'ERROR: {E}')
      break
    print(f'Przesunął z kolejki {Q}')
    print(f'APPEND({2*Q})')
    cQUEUE.APPEND(Q*2)
    cQUEUE.SHOW()
  for i in range(6):
    try:
      Q=cQUEUE.SHIFT()
      print(f'Przesunął z kolejki {Q}')
    except Exception as E:
      print(f'ERROR: {E}')
      break
    cQUEUE.SHOW()






