def init_windows(self):
        self.stdscr = curses.initscr()
        self.stdscr.clear()
        self.stdscr.nodelay(True)
        curses.start_color()

        self.main_window = MainWindow(self.stdscr)
        self.warning_windows = []
class Monitor:
    def __init__(self, args):
        self.controls = {}
        self.init_windows()
        self.godname = args.god_name
        self.dump_file = args.state
        self.state = {}
        self.notification_command = args.notification_command
        self.quiet = args.quiet
        self.browser = args.browser if args.browser else "x-www-browser"
        self.refresh_command = args.refresh_command
        self.autorefresh = args.autorefresh
        self.open_browser_on_start = args.open_browser_on_start
        self.token = args.token
        self.rules = []
        self.prev_state = None
        self.error = None

        curses.noecho()
        try:
            curses.cbreak()
        except curses.error:
            logging.error('curses error: cbreak returned ERR, probably invalid terminal. Try screen or tmux.')
            pass

        self.init_colors()
        self.init_keys()
        self.init_status_checkers()

    def finalize(self):
        curses.echo()
        try:
            curses.nocbreak()
        except curses.error:
            logging.error('curses error: cbreak returned ERR, probably invalid terminal. Try screen or tmux.')
            pass
        curses.endwin()

    def init_keys(self):
        self.controls['q'] = self.quit
        self.controls['f'] = self.open_browser
        self.controls['F'] = self.refresh_session
        self.controls[' '] = self.remove_warning

    def init_windows(self):
        self.stdscr = curses.initscr()
        self.stdscr.clear()
        self.stdscr.nodelay(True)
        curses.start_color()

        self.main_window = MainWindow(self.stdscr)
        self.warning_windows = []

    def init_colors(self):
        curses.use_default_colors()
        COLOR_TRANSPARENT = -1
        curses.init_pair(Colors.STANDART,
                         curses.COLOR_WHITE,
                         COLOR_TRANSPARENT)

        curses.init_pair(Colors.HEALTH_POINTS,
                         curses.COLOR_RED,
                         COLOR_TRANSPARENT)

        curses.init_pair(Colors.POWER_POINTS,
                         curses.COLOR_BLUE,
                         COLOR_TRANSPARENT)

        curses.init_pair(Colors.ATTENTION,
                         curses.COLOR_WHITE,
                         curses.COLOR_RED)
        curses.init_pair(Colors.MONEY,
                         curses.COLOR_YELLOW,
                         COLOR_TRANSPARENT)
        curses.init_pair(Colors.HEALING,
                         curses.COLOR_GREEN,
                         COLOR_TRANSPARENT)

    def post_warning(self, warning_message):
        if self.quiet:
            return
        if self.notification_command:
            os.system(self.notification_command.format(warning_message)) # FIXME: Highly insecure!
        self.warning_windows.append(WarningWindow(self.stdscr, warning_message))

    def remove_warning(self):
        if len(self.warning_windows) != 0:
            del self.warning_windows[-1]

        self.main_window.update(self.state)

    def handle_expired_session(self):
        if self.autorefresh:
            if self.expired_on_start:
                self.expired_on_start = False
                if self.open_browser_on_start:
                    self.open_browser()
                else:
                    self.refresh_session()
            else:
                self.refresh_session()
        else:
            self.post_warning(tr('Session is expired. Please reconnect.'))

    def init_status_checkers(self):
        self.rules.append(Rule(
            lambda info: 'expired' in info and info['expired'],
            self.handle_expired_session
            ))
        for custom_rule in CUSTOM_RULES:
            action = custom_rule(None)
            if isinstance(action, str) or isinstance(action, unicode):
                # Trick to bind message text at the creation time, not call time.
                action = lambda action=action: self.post_warning(action)
            self.rules.append(Rule(custom_rule, action))

    def read_state(self):
        logging.debug('%s: reading state',
                      self.read_state.__name__)

        state = None

        try:
            if self.dump_file != None:
                state = self.read_dump(self.dump_file)
            else:
                state = load_hero_state(self.godname, self.token)
            self.error = None
        except urllib.error.URLError as e:
            logging.error('%s: reading state error \n %s',
                          self.read_state.__name__,
                          str(e))
            self.post_warning(tr('Connection error: {0}').format(e))
            if self.prev_state is None:
                print(tr('Error occured, please see the pygod.log'))
                sys.exit(1)
            state = self.prev_state
            self.error = str(e)
        except Exception as e:
            logging.error('%s: reading state error \n %s %s %s',
                          self.read_state.__name__,
                          str(type(e)), repr(e), str(e))
            print(tr('Error occured, please see the pygod.log'))

            sys.exit(1)
        if 'token_expired' in state:
            self.post_warning(tr('Token is expired.\n'
                    'Visit user profile page to generate a new one:\n'
                    'https://godville.net/user/profile'
                    ))
        self.prev_state = state
        return state

    def read_dump(self, dumpfile):
        state = None

        try:
            state = load_hero_state(self.godname, filename=dumpfile)
        except IOError:
            logging.error('%s: Error reading file %s',
                          self.read_dump.__name__,
                          dumpfile)

        return state

    def handle_key(self):
        try:
            key = self.stdscr.getkey()
            if key in self.controls:
                self.controls[key]()
        except curses.error as e:
            if not 'no input' in e.args:
                raise

    def quit(self):
        sys.exit(0)

    def open_browser(self):
        subprocess.Popen("{0} http://godville.net/superhero".format(self.browser), shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # FIXME also unsafe!

    def refresh_session(self):
        if self.refresh_command:
            subprocess.Popen(self.refresh_command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # FIXME also unsafe!

    def check_status(self, state):
        for rule in self.rules:
            rule.check(state)

    def main_loop(self):
        UPDATE_INTERVAL = 61
        last_update_time = time.time()

        self.state = self.read_state()
        if self.error:
            self.state['error'] = self.error
        self.expired_on_start = 'expired' in self.state and self.state['expired']
        self.check_status(self.state)
        self.main_window.update(self.state)

        while(True):
            if last_update_time + UPDATE_INTERVAL < time.time():
                last_update_time = time.time()
                self.state = self.read_state()
                self.check_status(self.state)
                self.main_window.update(self.state)

            if len(self.warning_windows) != 0:
                self.warning_windows[-1].update({})

            self.handle_key()
            time.sleep(0.1)