import curses
import time

############################################
#       1. how to start curses             #
############################################


if False: # some dummy code...

   # makes terminal go into curses mode,
   # `stdscr` is a curses window.
   stdscr = curses.initscr()

   # makes text not be echoed in the window
   curses.noecho()

   # makes curses respond to character input
   # immediately (ie. don't have to press ENTER)
   curses.cbreak()

   curses.nocbreak()

### also there is stuff that has to do with
### restarting the terminal in non-curses mode
### after the program is finished (because the
### terminal will be all messed-up otherwise).
###
### but... we don't have to worry about any of
### that because we are using `curses.wrapper`


############################################
#        2. a curses program               #
############################################

# this function definition contains an actual curses program.

def the_program(stdscr):
   """
   intended to be used as Callable
   argument to curses.wrapper()
   """
   curses.noecho()
   curses.cbreak()
   # making the cursor invisible
   CURSOR_VISIBILITY = {
       "invisible": 0,
       "visibile": 1,
       "very_visible": 2
   }
   curses.curs_set(CURSOR_VISIBILITY["invisible"])
   # not that most of the curses attributes are globals:
   # when we set them, they will stay that way until
   # we change them to something else.


   # means that the window will be erased
   # and re-drawn the next time that `stdscr.refresh()`
   # is called.
   stdscr.clear()

   # placing a string at the top-left corner of
   # the window.
                #y #x  #the str
   stdscr.addstr(0, 0, "hi bud")

   # actually printing this screen
   stdscr.refresh()

   # getting the dimensions of the window.
   max_y, max_x = stdscr.getmaxyx()

   # adding a string listing the dimensions
   # to the center of the window
   xy_str = "current window is {} chars wide"\
       "and {} chars tall.".format(max_x, max_y)

                              #floor division!
   offset_x = (max_x - len(xy_str)) // 2
   offset_y = max_y // 2
                   #y         #x   #the str
   stdscr.addstr(offset_y, offset_x, xy_str)

   ## printing "#" at the corner of the window OPPOSITE to (0,0)
   stdscr.addstr(max_y - 1, max_x - 2, "#")
   #################################################################
   ### interesting fact: i don't know why, but curses will throw an
   ### error if we tried to print a character at `max_x - 1`
   ### (probably 79, for a standard 80x24 char terminal).
   ###
   ### it does this, even though we made the cursor invisible.
   #################################################################

   # actually printing the updates
   stdscr.refresh()

   #################################################################
   #
   # P     ### ### ###
   # A    ### ### ###
   # R   ### ### ###
   # T  ### ### ###
   #
   #################################################################

   # now we will take some user input.

   # first, print another message so the user
   # knows what to do.
   # it will be printed at the bottom of the screen,
   # like the message line in GNU emacs.


   exit_msg = "press any key to exit"
   stdscr.addstr(
       max_y - 1, # y
       (max_x - len(exit_msg)) // 2, # x
       exit_msg # string
   )

   stdscr.refresh()

   # the program will block here, until a button is pressed.
   character = stdscr.getch()

   # PLAYING A TRICK ON THE USER!!! #


   # erasing the screen
   stdscr.clear()

   # show the user input
   curses.echo()

   trick_msg = "please enter the name of your operating system"
   trick_msg_pos = {
       "y": max_y // 2,
       "x": (max_x - len(trick_msg)) // 2
   }
   stdscr.addstr(
       trick_msg_pos["y"],
       trick_msg_pos["x"],
       trick_msg
   )
   # now we will use `stdscr.getstr` to get a
   # "line-delimited" string, and put the
   # cursor is a visually pleasing central position

   # first we will make the cursor nice and visible again
   curses.curs_set(CURSOR_VISIBILITY["very_visible"])

   user_os_bytes = stdscr.getstr( # `y` and `x` position cursor
       trick_msg_pos["y"] + 2, # 2 lines below the message
       trick_msg_pos["x"],     # same justification as message
   )

   #################################################################
   ### HOW TO BYTES->STRING ########################################
   ### for some reason, the string is read as bytes.
   ### we can fix this easily by using utf8 encoding.
   #################################################################

   user_os = user_os_bytes.decode("utf-8")

   # updating
   stdscr.refresh()

   # erase again
   stdscr.clear()

   curses.noecho()

   you_said_msg = "you said: {}".format(user_os)
   you_said_msg_pos = {
       "y": max_y // 2,
       "x": (max_x - len(you_said_msg)) // 2
   }

   stdscr.addstr(
       you_said_msg_pos["y"],
       you_said_msg_pos["x"],
       you_said_msg
   )
   stdscr.refresh()


   # NOW the CLOWNING begins...

   # suspend execution for comedic timing
   time.sleep(1.5)

   ms_msg_1 = "MICRO$UX WINBLOWZ"
   ms_msg_2 = " detected"

   total_len = len(ms_msg_1) + len(ms_msg_2)
   ms_msg_x = (max_x - total_len) // 2

   stdscr.addstr(
       you_said_msg_pos["y"] + 2,
       ms_msg_x,
       ms_msg_1,
       # `addstr` has a fourth, optional parameter that accepts a
       # SINGLE attribute.
       curses.A_BOLD, # this text will be bold
   )

   # this part of the message will immediately
   # follow the first part, on the same line.
   stdscr.addstr(
       you_said_msg_pos["y"] + 2,
       ms_msg_x + len(ms_msg_1),
       ms_msg_2,
       curses.A_ITALIC # also italic
   )

   # make cursor invisible again
   curses.curs_set(CURSOR_VISIBILITY["invisible"])
   stdscr.refresh()

   # more timing
   time.sleep(1)


   update_msg = "press any key to do windoze updates"
   stdscr.addstr(
       you_said_msg_pos["y"] + 4,
       (max_x - len(update_msg)) // 2,
       update_msg
   )

   stdscr.getch()

   for i in range(100):
       stdscr.clear()

       progress_msg = "your windoze are {}% updated".format(i)
       doing_msg = "doing WINDOZE UPDATES"

       stdscr.addstr(
           max_y // 2,
           (max_x - len(progress_msg)) // 2,
           progress_msg,
           curses.A_BOLD
       )

       stdscr.addstr(
           (max_y // 2) - 2,
           (max_x - len(doing_msg)) // 2,
           doing_msg,
           curses.A_BLINK # it blinks!
       )

       stdscr.refresh()

       # make it nice and slow :]
       time.sleep(2)

# we actually run the program in our
# `__name__ == ...` block

if __name__ == "__main__":
   curses.wrapper(the_program)





#Attribute Meanings

# A_ALTCHARSET
# Alternate character set mode

# A_BLINK
#
#
# Blink mode
#
# A_BOLD
#
#
# Bold mode
#
# A_DIM
#
#
# Dim mode
#
# A_INVIS
#
#
# Invisible or blank mode
#
# A_ITALIC
#
#
# Italic mode
#
# A_NORMAL
#
#
# Normal attribute
#
# A_PROTECT
#
#
# Protected mode
#
# A_REVERSE
#
#
# Reverse background and foreground colors
#
# A_STANDOUT
#
#
# Standout mode
#
# A_UNDERLINE
#
#
# Underline mode
#
# A_HORIZONTAL
#
#
# Horizontal highlight
#
# A_LEFT
#
#
# Left highlight
#
# A_LOW
#
#
# Low highlight
#
# A_RIGHT
#
#
# Right highlight
#
# A_TOP
#
#
# Top highlight
#
# A_VERTICAL
#
#
# Vertical highlight
#
# A_CHARTEXT
#
#
# Bit-mask to extract a character