import datetime
from unittest import mock
import urllib.parse

from absl.testing import absltest
from google.oauth2 import credentials as authorized_user
from google.oauth2 import service_account
from protorpc import protojson

from multitest_transport.api import api_test_util
from multitest_transport.api import build_channel_api
from multitest_transport.models import build
from multitest_transport.models import messages
from multitest_transport.models import ndb_models
from multitest_transport.plugins import base as plugins
from multitest_transport.util import file_util

class AndroidBuildProvider(plugins.BuildProvider):
  """Dummy build provider for testing."""
  name = 'Android'
  mock = mock.MagicMock()
  build_item_path_type = plugins.BuildItemPathType.DIRECTORY_FILE

  def __init__(self):
    super(AndroidBuildProvider, self).__init__()
    self.AddOptionDef('mock_option')

  def GetBuildItem(self, path):
    return self.mock.GetBuildItem(path)

class GoogleDriveBuildProvider(plugins.BuildProvider):
  """Dummy build provider for testing."""
  name = 'Google Drive'
  build_item_path_type = plugins.BuildItemPathType.DIRECTORY_FILE

class BuildChannelApiTest(api_test_util.TestCase):

  def setUp(self):
    super(BuildChannelApiTest, self).setUp(build_channel_api.BuildChannelApi)

  def _CreateMockBuildChannel(self, name='android', provider='Android'):
    return build.AddBuildChannel(name, provider, {})

  def testList(self):
    self._CreateMockBuildChannel(name='android', provider='Android')
    self._CreateMockBuildChannel(name='drive', provider='Google Drive')

    res = self.app.get('/_ah/api/mtt/v1/build_channels')
    build_channel_list = protojson.decode_message(
        messages.BuildChannelList, res.body)

    # verify that the right channels are returned
    build_channels = build_channel_list.build_channels
    self.assertEqual(2, len(build_channels))
    self.assertItemsEqual(['android', 'drive'], [
        channel.name for channel in build_channels])
    self.assertItemsEqual(['Android', 'Google Drive'], [
        channel.provider_name for channel in build_channels])

  def testGet(self):
    config = self._CreateMockBuildChannel()

    res = self.app.get('/_ah/api/mtt/v1/build_channels/%s' % config.key.id())
    build_channel_config = protojson.decode_message(messages.BuildChannelConfig,
                                                    res.body)

    # verify that the right channel is returned
    self.assertEqual(config.key.id(), build_channel_config.id)
    self.assertEqual('android', build_channel_config.name)

  def testGet_notFound(self):
    # unknown build channel ID
    res = self.app.get('/_ah/api/mtt/v1/build_channels/%s' % 666,
                       expect_errors=True)
    # throws if channel not found
    self.assertEqual('404 Not Found', res.status)

  @mock.patch.object(build.BuildChannel, 'ListBuildItems')
  def testListBuildItems(self, mock_channel):
    # create placeholders build items to return from channel
    build_items = [
        plugins.BuildItem(name='item1', path=u'path1', is_file=True),
        plugins.BuildItem(name='item2', path=u'path2', is_file=True)
    ]
    mock_channel.return_value = build_items, 'next_page_token'
    config = self._CreateMockBuildChannel()

    res = self.app.get(
        '/_ah/api/mtt/v1/build_channels/%s/build_items' % config.key.id())
    build_item_list = protojson.decode_message(messages.BuildItemList, res.body)

    # verify same build items are returned
    self.assertEqual('next_page_token', build_item_list.next_page_token)
    self.assertItemsEqual(['item1', 'item2'], [
        item.name for item in build_item_list.build_items])

  def testListBuildItems_notFound(self):
    # unknown build channel ID
    res = self.app.get('/_ah/api/mtt/v1/build_channels/%s/build_items' % 666,
                       expect_errors=True)
    # throws if channel not found
    self.assertEqual('404 Not Found', res.status)

  def testLookupBuildItem(self):
    config = self._CreateMockBuildChannel(name='android', provider='Android')
    url = 'mtt:///%s/path/to/file.ext' % config.key.id()
    build_item = plugins.BuildItem(
        name='foo',
        path='zzz/bar/foo',
        is_file=True,
        size=1234,
        timestamp=datetime.datetime.utcnow())
    AndroidBuildProvider.mock.GetBuildItem.return_value = build_item

    res = self.app.get(
        '/_ah/api/mtt/v1/build_channels/build_item_lookup?url=%s' % (
            urllib.parse.quote(url)))
    build_item_msg = protojson.decode_message(messages.BuildItem, res.body)

    AndroidBuildProvider.mock.GetBuildItem.assert_called_once_with(
        'path/to/file.ext')
    self.assertEqual(
        messages.Convert(build_item, messages.BuildItem), build_item_msg)

  @mock.patch.object(file_util.FileHandle, 'Get')
  def testLookupBuildItem_withHttpUrl(self, mock_find_handle_get):
    url = 'http://foo.com/bar/zzz/file.ext?foo=bar'
    mock_file_handle = mock.MagicMock()
    mock_find_handle_get.return_value = mock_file_handle
    mock_file_info = file_util.FileInfo(
        url=url,
        is_file=True,
        total_size=1234,
        timestamp=datetime.datetime.utcnow())
    mock_file_handle.Info.return_value = mock_file_info

    res = self.app.get(
        '/_ah/api/mtt/v1/build_channels/build_item_lookup?url=%s' % (
            urllib.parse.quote(url)))
    build_item_msg = protojson.decode_message(messages.BuildItem, res.body)

    mock_find_handle_get.assert_called_once_with(url)
    mock_file_handle.Info.assert_called_once()
    self.assertEqual('file.ext', build_item_msg.name)
    self.assertEqual(mock_file_info.is_file, build_item_msg.is_file)
    self.assertEqual(mock_file_info.total_size, build_item_msg.size)
    self.assertEqual(mock_file_info.timestamp, build_item_msg.timestamp)

  def testDelete(self):
    # create build channel and confirm it exists
    config = self._CreateMockBuildChannel()
    self.assertIsNotNone(config.key.get())

    # delete channel and verify that it no longer exists
    self.app.delete('/_ah/api/mtt/v1/build_channels/%s' % config.key.id())
    self.assertIsNone(config.key.get())

  def testCreate(self):
    data = {
        'name': 'testName',
        'id': '',
        'provider_name': 'Android',
        'options': [{
            'name': 'mock_option',
            'value': '123123123'
        }]
    }
    res = self.app.post_json('/_ah/api/mtt/v1/build_channels', data)
    msg = protojson.decode_message(messages.BuildChannelConfig, res.body)
    build_channel_config = messages.ConvertToKey(ndb_models.BuildChannelConfig,
                                                 msg.id).get()
    self.assertIsNotNone(build_channel_config)
    self.assertEqual(data['name'], build_channel_config.name)
    self.assertEqual(data['provider_name'], build_channel_config.provider_name)
    self.assertEqual(data['options'][0]['name'],
                     build_channel_config.options[0].name)

  def testUpdate(self):
    build_channel_config = self._CreateMockBuildChannel()
    build_channel_config_id = str(build_channel_config.key.id())
    data = {
        'id': build_channel_config_id,
        'name': 'bar',
        'provider_name': 'Android'
    }
    res = self.app.put_json(
        '/_ah/api/mtt/v1/build_channels/%s' % build_channel_config_id, data)

    build_channel_config = build_channel_config.key.get()
    msg = protojson.decode_message(messages.BuildChannelConfig, res.body)
    self.assertEqual(
        messages.Convert(build_channel_config, messages.BuildChannelConfig),
        msg)
    self.assertEqual(data['name'], build_channel_config.name)

  @mock.patch.object(service_account.Credentials, 'from_service_account_info')
  def testAuthorizeConfigWithServiceAccount(self, mock_parse_key):
    """Tests that a build channel can be authorized with a service account."""
    config = self._CreateMockBuildChannel(name='android', provider='Android')
    # Mock parsing service account JSON key
    mock_parse_key.return_value = service_account.Credentials(None, None, None)
    # Verify that credentials were obtained and stored
    self.app.put_json(
        '/_ah/api/mtt/v1/build_channels/%s/auth' % config.key.id(),
        {'value': '{}'})
    config = ndb_models.BuildChannelConfig.get_by_id(config.key.id())
    self.assertIsNotNone(config.credentials)

  def testAuthorizeWithServiceAccount_notFound(self):
    """Tests that an error occurs when a build channel is not found."""
    response = self.app.put_json(
        '/_ah/api/mtt/v1/build_channels/%s/auth' % 'unknown', {'value': '{}'},
        expect_errors=True)
    self.assertEqual('404 Not Found', response.status)

  def testUnauthorize(self):
    """Tests that a build channel can be unauthorized."""
    config = self._CreateMockBuildChannel(name='android', provider='Android')
    config.credentials = authorized_user.Credentials(None)
    config.put()
    # Verify that credentials were removed
    self.app.delete('/_ah/api/mtt/v1/build_channels/%s/auth' % config.key.id())
    config = ndb_models.BuildChannelConfig.get_by_id(config.key.id())
    self.assertIsNone(config.credentials)

  def testUnauthorize_notFound(self):
    """Tests that an error occurs when a build channel is not found."""
    response = self.app.delete(
        '/_ah/api/mtt/v1/build_channels/%s/auth' % 'unknown',
        expect_errors=True)
    self.assertEqual('404 Not Found', response.status)

if __name__ == '__main__':
  absltest.main()


# %%
from binance import Client
import personal_function as pf
import pandas as pd
import numpy as np
import mplfinance as mpf
from binance.enums import *
import datetime  # For datetime objects
import sys  # To find out the script name (in argv[0])
import backtrader as bt

# %%
client=pf.client()

KlinesType ='SPOT'
symbol ='BTCUSDT'
interval = '4h' # 30m, 4h,8h,12h,3d,1w
start_date ='1 Jan 2011'
end_date = '1 Jan 2021'
#limit = 500
hist_df=pf.historical_data(client,symbol, interval, start_date, end_date, KlinesType)

# %%
training_df=hist_df[0:int((hist_df.shape[0]/2))+1]
training_df.to_csv('{}_training.csv'.format(symbol))
test_df=hist_df[int((hist_df.shape[0]/2))+1:]
test_df.to_csv('{}_test.csv'.format(symbol))

# %%
class MACD(bt.Strategy):
    '''
    This strategy is loosely based on some of the examples from the Van
    K. Tharp book: *Trade Your Way To Financial Freedom*. The logic:

      - Enter the market if:
        - The MACD.macd line crosses the MACD.signal line to the upside
        - The Simple Moving Average has a negative direction in the last x
          periods (actual value below value x periods ago)

     - Set a stop price x times the ATR value away from the close

     - If in the market:

       - Check if the current close has gone below the stop price. If yes,
         exit.
       - If not, update the stop price if the new stop price would be higher
         than the current
    '''

    params = (
        # Standard MACD Parameters
        ('macd1', 12),
        ('macd2', 26),
        ('macdsig', 9),
        ('atrperiod', 14),  # ATR Period (standard)
        ('atrdist', 3.0),   # ATR distance for stop price
        ('smaperiod', 30),  # SMA Period (pretty standard)
        ('dirperiod', 10),  # Lookback period to consider SMA trend direction
    )

    def notify_order(self, order):
        if order.status == order.Completed:
            pass

        if not order.alive():
            self.order = None  # indicate no order is pending

    def __init__(self):
        self.macd = bt.indicators.MACD(self.data,
                                       period_me1=self.p.macd1,
                                       period_me2=self.p.macd2,
                                       period_signal=self.p.macdsig)

        # Cross of macd.macd and macd.signal
        self.mcross = bt.indicators.CrossOver(self.macd.macd, self.macd.signal)

        # To set the stop price
        self.atr = bt.indicators.ATR(self.data, period=self.p.atrperiod)

        # Control market trend
        self.sma = bt.indicators.SMA(self.data, period=self.p.smaperiod)
        self.smadir = self.sma - self.sma(-self.p.dirperiod)

    def start(self):
        self.order = None  # sentinel to avoid operrations on pending order

    def next(self):
        if self.order:
            return  # pending order execution

        if not self.position:  # not in the market
            if self.mcross[0] > 0.0 and self.smadir < 0.0:
                self.order = self.buy()
                pdist = self.atr[0] * self.p.atrdist
                self.pstop = self.data.close[0] - pdist

        else:  # in the market
            pclose = self.data.close[0]
            pstop = self.pstop

            if pclose < pstop:
                self.close()  # stop met - get out
            else:
                pdist = self.atr[0] * self.p.atrdist
                # Update only if greater than
                self.pstop = max(pstop, pclose - pdist)

# %%
if __name__ == '__main__':
    data=bt.feeds.GenericCSVData(
    dataname='{}_training.csv'.format(symbol),
    fromdate=datetime.datetime(2017,8,17,4,0,0),
    todate=datetime.datetime(2019,4,26,8,0,0),
    datetime=1,
    open=2,
    high=3,
    low=4,
    close=5,
    volume=6,
    dtformat=('%Y-%m-%d %H:%M:%S'),
    tmformat=('%H:%M:%S'),
    timeframe=bt.feeds.TimeFrame.Ticks
)
    cerebro = bt.Cerebro()
    cerebro.addstrategy(MACD)
    cerebro.adddata(data)
    cerebro.broker.setcash(100000.0)
    cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='mysharpe')
    cerebro.addsizer(bt.sizers.SizerFix, stake=30)

    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    thestrats=cerebro.run()
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    thestrat = thestrats[0]
    print('Sharpe Ratio:',  thestrat.analyzers.mysharpe.get_analysis())
    cerebro.plot()


import csv
import matplotlib.pyplot as plt
import numpy as np

category = []
germany = []
finland = []
italy = []

with open('data/OlympicsWinter.csv') as csvfile:
    reader = csv.reader(csvfile)
    line_count = 0

    for row in reader:
        if line_count is 0:
            category.append(row)
            line_count += 1
        elif row[4] == "GER":
            germany.append([int(row[0]), row[5], row[6], row[7]])
        elif row[4] == "FIN":
            finland.append([int(row[0]), row[5], row[6], row[7]])
            line_count += 1
        elif row[4] == "ITA":
            italy.append([int(row[0]), row[5], row[6], row[7]])
            line_count += 1

silver_1924 = []
silver_1948 = []
silver_1972 = []

# Silver medals in Germany
for medal in germany:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

# Silver medals in Finland
for medal in finland:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

# Silver medals in Italy
for medal in italy:
    if medal[0] == 1924 and medal[3] == "Silver":
        silver_1924.append(medal)

    if medal[0] == 1948 and medal[3] == "Silver":
        silver_1948.append(medal)

    if medal[0] == 1972 and medal[3] == "Silver":
        silver_1972.append(medal)

print('Silver medals in Germany won from \'1924 to 1972', len(germany))
print('Silver medals in Finland has won since \'1924 to 1972', len(finland))
print('Silver medals in Italy won in \'1924 to 1972', len(italy))

totalSilverMedals = len(germany) + len(finland) + len(italy)

# percentages of three countries for silver medals
germany_pertencage = int(len(germany)) / totalSilverMedals * 100
finland_pertencage = int(len(finland)) / totalSilverMedals * 100
italy_pertencage = int(len(italy)) / totalSilverMedals * 100

print(germany_pertencage, finland_pertencage, italy_pertencage)

print('count', line_count, 'total silver medals:', totalSilverMedals)

# Pie Chart
labels = "Germany", "Finland", "Italy"
sizes = [germany_pertencage, finland_pertencage, italy_pertencage]
colors = ["dimgrey", "darkgrey", "gainsboro"]
explode = (0.1, 0.1, 0.1)

plt.pie(sizes, explode=explode, colors=colors, autopct='%1.1f%%', shadow=True, startangle=140)

plt.axis('equal')
plt.legend(labels, loc=1)
plt.title("SILVER MEDALS WON IN THREE COUNTRIES")
plt.xlabel("Silver Medals from 1924, 1948, and 1972")
plt.show()

# Horizontal bar chart
# Fixing random state for reproducibility
np.random.seed(19680801)

labels = "Germany", "Finland", "Italy"
sizes = [germany_pertencage, finland_pertencage, italy_pertencage]
colors = ["dimgrey", "darkgrey", "gainsboro"]

plt.rcdefaults()
fig, ax = plt.subplots()

y_ind = np.arange(len(labels))
error = np.random.rand(len(labels))
ax.barh(y_ind, sizes, xerr=error, align='center', color=colors)
ax.set_yticks(y_ind)
ax.set_yticklabels(labels)
ax.invert_yaxis()
ax.set_xlabel("Total silver medals in 1924, 1948, and 1972")
ax.set_title("SILVER MEDALS WON IN THREE COUNTRIES")
plt.show()


try:
    import constants, os, pygame, sound_mixer, graphics
    from os_utils import file_path, safe_exit
    from utils import get_time_sec
    from anim_sprite import *
    from credits import Credits
    from kezmenu import KezMenu
    from fsm import State
except ImportError as err:
    try:
        import os
        path = os.path.basename(__file__)
        print((': '.join((path, str(err)))))
    # importing os failed, print a custom message...
    except ImportError:
        print((': '.join(("couldn't load module", str(err)))))
    exit(2)

## objects imported when `from <module> import *' is used
__all__ = ['Menu']

## the main menu's position x co-ordinate
MENU_MAIN_POS_X = 525

## the main menu's position y co-ordinate
MENU_MAIN_POS_Y = 285

## menu keyboard repeat delay
MENU_KEY_DEL = 500

## menu keyboard repeat interval
MENU_KEY_INT = 200

## animated sprite speed
ANIM_SPRITE_SPEED = 200.0

## animated sprite alpha (on settings)
ANIM_SPRITE_ALPHA = 80.0

MAIN_FONT_SIZE = 32
MENU_FONT_SIZE = 25
MAIN_FOCUS_COLOR = pygame.Color('brown')
SETTINGS_FOCUS_COLOR = pygame.Color('orange')
MENU_CLOCK_TICK = 50
SOUND_VOL = 0.2
MAX_ALPHA = 255

## class for game's menu screen
#
class Menu(State):

    ## initialize both the main and settings menu
    #
    # @param self the object pointer
    # @param game_opts the game's command line options
    def __init__(self, game_opts):
        # initialize the state
        State.__init__(self, constants.SCENES['menu'])

        ## the game's command line options
        self.game_opts = game_opts

        ## the screen surface
        self.screen = pygame.display.get_surface()

        ## flag to control the settings menu's loop
        self.menu_settings_running = None

        ## flag to control the main menu's loop
        self.menu_main_running = True

        # enable key repeat for the menu
        pygame.key.set_repeat(MENU_KEY_DEL, MENU_KEY_INT)

        ## set the main menu's background
        self.menu_main_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['main']['bg'][0])[0]

        ## set the settings menu's background
        self.menu_settings_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['bg'][0])[0]

        ## set the settings menu's background box
        self.menu_box_bg = graphics.load_image(
            constants.FILES['graphics']['menu']['settings']['box'][0])[0]

        ## set the window frame
        self.window_frame = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['frame'][0])[0]

        ## set the mouse cursor
        self.mouse_cursor = graphics.load_image(
            constants.FILES['graphics']['menu']['share']['cursor'][0])[0]

        ## set the sound when a menu option is entered
        self.select_option_snd = sound_mixer.load_sound(
            constants.FILES['sounds']['menu']['share']['sel'][0])

        ## create the main menu - string, callback function
        self.menu_main = KezMenu(self.game_opts,
                         ['Play'     , self._play_option],
                         ['Settings' , self._settings_option],
                         ['Credits'  , self._credits_option],
                         ['Quit'     , self._quit_option])

        # set the position of the main menu
        self.menu_main.set_position(MENU_MAIN_POS_X, MENU_MAIN_POS_Y)

        # set the main menu's font
        self.menu_main.set_font(graphics.load_font(
            constants.FILES['fonts']['menu']['share'][0], MAIN_FONT_SIZE))

        # set the main menu's highlight color
        self.menu_main.set_highlight_color(MAIN_FOCUS_COLOR)

        ## create the settings menu - string, callback function
        self.menu_settings = KezMenu(self.game_opts,
                             ['Fullscreen' , self._toggle_fullscreen_option],
                             ['Sounds'     , self._toggle_sounds_option],
                             ['Music'      , self._toggle_music_option],
                             ['Back'       , self._back_option])

        # disable the menu graphic for focused options
        self.menu_settings.toggle_image()

        # set the settings menu's font
        self.menu_settings.set_font(graphics.load_font(
            constants.FILES['fonts']['menu']['share'][0], MENU_FONT_SIZE))

        # set the position of the settings menu
        self.menu_settings.center_at(constants.SCREEN_WIDTH / 2.0,
                                     constants.SCREEN_HEIGHT / 2.0)

        # set the settings menu's highlight color
        self.menu_settings.set_highlight_color(SETTINGS_FOCUS_COLOR)

        ## the animated sprite group
        self.anim_sprites = pygame.sprite.RenderUpdates()

        # create the animated sprites
        sprite_num = len(constants.FILES['graphics']['menu']['share']['anim'])
        sprite_fact = SpriteFactory()
        for i in range(sprite_num):
            # create the "right" type of animated sprite using the factory
            r_sprite = sprite_fact.create_anim_sprite(i, constants.FILES['graphics']['menu']
                                                      ['share']['anim'][i], ANIM_SPRITE_SPEED)
            self.anim_sprites.add(r_sprite)

        ## create clock and track time
        self.clock = pygame.time.Clock()

    ## what to do when the main menu is enabled
    #
    # @param self the object pointer
    def do_actions(self):

        # display & update screen, get all the events
        while self.menu_main_running:

            # draw the background
            bg = self.screen.blit(self.menu_main_bg, (0, 0))

            # count time passed in seconds
            time_passed_seconds = get_time_sec(self.clock.tick(MENU_CLOCK_TICK))

            # animate the sprites
            self.anim_sprites.update(time_passed_seconds)

            # rectlist = self.anim_sprites.draw(self.screen)
            self.anim_sprites.draw(self.screen)

            # draw the main menu
            self.menu_main.draw(self.screen)

            # draw the custom mouse cursor
            graphics.handle_mouse_cursor(self.mouse_cursor, self.screen)

            # draw the frame of the window
            fr = self.screen.blit(self.window_frame, (0, 0))

            need_update = (bg, fr)

            # display the screen surface
            pygame.display.update(need_update)

            # get all the events
            events = pygame.event.get()

            # ......... and update the main menu
            # which needs access to those events
            self.menu_main.update(events)

            # main menu event loop
            for e in events:
                # quit when the close button is pressed
                if e.type == pygame.QUIT:
                    self._quit_option()
                # handle keyboard keys
                elif e.type == pygame.KEYDOWN:
                    # play the sound if there was a menu key shortcut
                    if self.game_opts.sound:
                        if e.key in (pygame.K_p, pygame.K_s, pygame.K_c):
                            sound_mixer.play_sound(
                                self.select_option_snd, SOUND_VOL)

                    # when user presses escape or 'q'uit key
                    if e.key in (pygame.K_ESCAPE, pygame.K_q):
                        self._quit_option()
                    # when user presses 'p'lay key
                    elif e.key == pygame.K_p:
                        self._play_option()
                    # when user presses 's'ettings key
                    elif e.key == pygame.K_s:
                        self._settings_option()
                    # when user presses 'c'redits key
                    elif e.key == pygame.K_c:
                        self._credits_option()

    ## entry point for main menu's settings option
    #
    # @param self the object pointer
    def _settings_option(self):
        # each time we enter in settings
        # sub menu, set the flag to true
        self.menu_settings_running = True

        # decrease the alpha of animated sprites
        for s in self.anim_sprites:
            s.image.set_alpha(ANIM_SPRITE_ALPHA)

        # display & update screen, get all the events
        while self.menu_settings_running:
            # draw the background
            bg = self.screen.blit(self.menu_settings_bg, (0, 0))

            # draw the main menu
            self.menu_main.draw(self.screen)

            # count time passed in seconds
            time_passed_seconds = get_time_sec(self.clock.tick(MENU_CLOCK_TICK))

            # animate the sprites
            self.anim_sprites.update(time_passed_seconds)
            self.anim_sprites.draw(self.screen)

            # draw settings menu background box
            menu_bg = self.screen.blit(self.menu_box_bg, (
                    (constants.SCREEN_WIDTH - self.menu_box_bg.get_width()) / 2.0,
                    (constants.SCREEN_HEIGHT - self.menu_box_bg.get_height()) / 2.0))

            # draw the settings menu
            self.menu_settings.draw(self.screen)

            # draw the custom mouse cursor
            graphics.handle_mouse_cursor(self.mouse_cursor, self.screen)

            # draw the frame of the window
            fr = self.screen.blit(self.window_frame, (0, 0))

            need_update = (bg, menu_bg, fr)

            # display the screen surface
            pygame.display.update(need_update)

            # get all the events
            events = pygame.event.get()

            # ..... and update the settings menu
            # which needs access to those events
            self.menu_settings.update(events)

            # settings menu event loop
            for e in events:
                # quit when the close button is pressed
                if e.type == pygame.QUIT:
                    self._back_option()
                    self._quit_option()
                # handle keyboard keys
                elif e.type == pygame.KEYDOWN:
                    # play the sound if there was a menu key shortcut
                    if self.game_opts.sound:
                        if e.key in (pygame.K_f, pygame.K_s, pygame.K_m,
                                     pygame.K_b, pygame.K_ESCAPE):
                            sound_mixer.play_sound(
                                self.select_option_snd, SOUND_VOL)

                    # when user presses escape key or 'b'ack key
                    if e.key in (pygame.K_ESCAPE, pygame.K_b):
                        self._back_option()
                    # when user presses 'f'ullscreen key
                    elif e.key == pygame.K_f:
                        self._toggle_fullscreen_option()
                    # when user presses 's'ounds key
                    elif e.key == pygame.K_s:
                        self._toggle_sounds_option()
                    # when user presses 'm'usic key
                    elif e.key == pygame.K_m:
                        self._toggle_music_option()

        # restore the alpha of the animated sprites
        for s in self.anim_sprites:
            s.image.set_alpha(MAX_ALPHA)

    ## entry point for main menu's new game option
    #
    # @param self the object pointer
    def _play_option(self):
        if self.game_opts.verbose:
            print('Start a new game.')
        self.menu_main_running = False

    ## what should be satisfied for enabling the next scene
    #
    # @param self the object pointer
    # @return the name of the next scene
    def check_conditions(self):
        # if the scene is finished, returns back
        # to the caller the name of the next one
        if not self.menu_main_running:
            return constants.SCENES['level_one']
        return None

    ## entry point for main menu's credits option
    #
    # @param self the object pointer
    def _credits_option(self):

        # get the path of the filename
        fullname = file_path(
            constants.FILES['texts']['menu']['credits']['text'][0],
            constants.TEXTS_DIR)

        # if credits text file exists and is readable
        if os.access(fullname, os.F_OK) and os.access(fullname, os.R_OK):
            if self.game_opts.verbose:
                print('Go to the credits screen.')

            # create the credits screen
            c = Credits(self.screen,
                        self.game_opts,
                        self.window_frame,
                        self.menu_settings_bg,
                        self.select_option_snd,
                        fullname)

            # run the credits screen
            if not c.run():
                # quit if the close button is
                # pressed (inside the credits)
                self._quit_option()
        else:
            print((' '.join(("Couldn't read text file:", fullname))))

    ## entry point for main menu's quit option
    #
    # @param self the object pointer
    def _quit_option(self):
        if self.game_opts.verbose:
            print('Exit the game!')

        # perform safe exit
        safe_exit()

    ## entry point for settings menu's toggle fullscreen option
    #
    # @param self the object pointer
    def _toggle_fullscreen_option(self):
        self.game_opts.fullscreen = not self.game_opts.fullscreen

        if self.game_opts.verbose:
            print('Toggle fullscreen!')

        # store the position of the mouse cursor
        mouse_position = pygame.mouse.get_pos()

        # toggle the fullscreen <-> window mode
        pygame.display.set_mode(
            (constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT),
            pygame.FULLSCREEN if self.game_opts.fullscreen else 0)

        # update the mouse cursor position
        pygame.mouse.set_pos(mouse_position)

    ## entry point for settings menu's toggle sounds option
    #
    # @param self the object pointer
    def _toggle_sounds_option(self):
        self.game_opts.sound = not self.game_opts.sound
        if self.game_opts.verbose:
            print('Toggle sounds!')

    ## entry point for settings menu's toggle music option
    #
    # @param self the object pointer
    def _toggle_music_option(self):
        if self.game_opts.verbose:
            print('Toggle music!')

        self.game_opts.music = not self.game_opts.music
        if self.game_opts.music:
            pygame.mixer.music.unpause()
        else:
            pygame.mixer.music.pause()

    ## entry point for settings menu's back option
    #
    # @param self the object pointer
    def _back_option(self):
        self.menu_settings_running = False
        if self.game_opts.verbose:
            print('Go back to main menu!')