# ==============================================================================
# Copyright (C) 2019 - Philip Paquette
#
#  This program is free software: you can redistribute it and/or modify it under
#  the terms of the GNU Affero General Public License as published by the Free
#  Software Foundation, either version 3 of the License, or (at your option) any
#  later version.
#
#  This program is distributed in the hope that it will be useful, but WITHOUT
#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
#  FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
#  details.
#
#  You should have received a copy of the GNU Affero General Public License along
#  with this program.  If not, see <https://www.gnu.org/licenses/>.
# ==============================================================================
""" Error
    - Contains the error messages and code used by the engine
"""
from diplomacy.utils.common import StringableCode

# Constants
MAP_ERROR_OFFSET = 20000
GAME_ERROR_OFFSET = 21000
STD_ERROR_OFFSET = 22000

class Error(StringableCode):
    """ Represents an error """

class MapError(Error):
    """ Represents a map error """
    def __init__(self, code, message):
        """ Build a MapError

            :param code: int code of the error
            :param message: human readable string message associated to the error
        """
        super(MapError, self).__init__(MAP_ERROR_OFFSET + code, message)

class GameError(Error):
    """ Represents a game error """
    def __init__(self, code, message):
        """ Build a GameError

            :param code: int code of the error
            :param message: human readable string message associated to the error
        """
        super(GameError, self).__init__(GAME_ERROR_OFFSET + code, message)

class StdError(Error):
    """ Represents a standard error """
    def __init__(self, code, message):
        """ Build a StdError

            :param code: int code of the error
            :param message: human readable string message associated to the error
        """
        super(StdError, self).__init__(STD_ERROR_OFFSET + code, message)

MAP_LEAST_TWO_POWERS = MapError(0, 'MAP DOES NOT SPECIFY AT LEAST TWO POWERS')
MAP_LOC_NOT_FOUND = MapError(1, 'NAMED LOCATION NOT ON MAP: %s')
MAP_SITE_ABUTS_TWICE = MapError(2, 'SITES ABUT TWICE %s-%s')
MAP_NO_FULL_NAME = MapError(3, 'MAP LOCATION HAS NO FULL NAME: %s')
MAP_ONE_WAY_ADJ = MapError(4, 'ONE-WAY ADJACENCY IN MAP: %s -> %s')
MAP_BAD_HOME = MapError(5, 'BAD HOME FOR %s: %s')
MAP_BAD_INITIAL_OWN_CENTER = MapError(6, 'BAD INITIAL OWNED CENTER FOR %s: %s')
MAP_BAD_INITIAL_UNITS = MapError(7, 'BAD INITIAL UNIT FOR %s: %s')
MAP_CENTER_MULT_OWNED = MapError(8, 'CENTER MULTIPLY OWNED: %s')
MAP_BAD_PHASE = MapError(9, 'BAD PHASE IN MAP FILE: %s')
MAP_FILE_NOT_FOUND = MapError(10, 'MAP FILE NOT FOUND: %s')
MAP_BAD_VICTORY_LINE = MapError(11, 'BAD VICTORY LINE IN MAP FILE')
MAP_BAD_ROOT_MAP_LINE = MapError(12, 'BAD ROOT MAP LINE')
MAP_TWO_ROOT_MAPS = MapError(13, 'TWO ROOT MAPS')
MAP_FILE_MULT_USED = MapError(14, 'FILE MULTIPLY USED: %s')
MAP_BAD_ALIASES_IN_FILE = MapError(15, 'BAD ALIASES IN MAP FILE: %s')
MAP_RENAME_NOT_SUPPORTED = MapError(16, 'THE RENAME PLACE OPERATOR -> IS NO LONGER SUPPORTED.')
MAP_BAD_RENAME_DIRECTIVE = MapError(17, 'BAD RENAME DIRECTIVE: %s')
MAP_INVALID_LOC_ABBREV = MapError(18, 'INVALID LOCATION ABBREVIATION: %s')
MAP_LOC_RESERVED_KEYWORD = MapError(19, 'MAP LOCATION IS RESERVED KEYWORD: %s')
MAP_DUP_LOC_OR_POWER = MapError(20, 'DUPLICATE MAP LOCATION OR POWER: %s')
MAP_DUP_ALIAS_OR_POWER = MapError(21, 'DUPLICATE MAP ALIAS OR POWER: %s')
MAP_OWNS_BEFORE_POWER = MapError(22, '%s BEFORE POWER: %s')
MAP_INHABITS_BEFORE_POWER = MapError(23, 'INHABITS BEFORE POWER: %s')
MAP_HOME_BEFORE_POWER = MapError(24, '%s BEFORE POWER: %s')
MAP_UNITS_BEFORE_POWER = MapError(25, 'UNITS BEFORE POWER')
MAP_UNIT_BEFORE_POWER = MapError(26, 'UNIT BEFORE POWER: %s')
MAP_INVALID_UNIT = MapError(27, 'INVALID UNIT: %s')
MAP_DUMMY_REQ_LIST_POWERS = MapError(28, 'DUMMIES REQUIRES LIST OF POWERS')
MAP_DUMMY_BEFORE_POWER = MapError(29, 'DUMMY BEFORE POWER')
MAP_NO_EXCEPT_AFTER_DUMMY_ALL = MapError(30, 'NO EXCEPT AFTER %s ALL')
MAP_NO_POWER_AFTER_DUMMY_ALL_EXCEPT = MapError(31, 'NO POWER AFTER %s ALL EXCEPT')
MAP_NO_DATA_TO_AMEND_FOR = MapError(32, 'NO DATA TO "AMEND" FOR %s')
MAP_NO_ABUTS_FOR = MapError(33, 'NO "ABUTS" FOR %s')
MAP_UNPLAYED_BEFORE_POWER = MapError(34, 'UNPLAYED BEFORE POWER')
MAP_NO_EXCEPT_AFTER_UNPLAYED_ALL = MapError(35, 'NO EXCEPT AFTER UNPLAYED ALL')
MAP_NO_POWER_AFTER_UNPLAYED_ALL_EXCEPT = MapError(36, 'NO POWER AFTER UNPLAYED ALL EXCEPT')
MAP_NO_SUCH_POWER_TO_REMOVE = MapError(37, 'NO SUCH POWER TO REMOVE: %s')
MAP_RENAMING_UNOWNED_DIR_NOT_ALLOWED = MapError(38, 'RENAMING UNOWNED DIRECTIVE NOT ALLOWED')
MAP_RENAMING_UNDEF_POWER = MapError(39, 'RENAMING UNDEFINED POWER %s')
MAP_RENAMING_POWER_NOT_SUPPORTED = MapError(40, 'THE RENAME POWER OPERATOR -> IS NO LONGER SUPPORTED.')
MAP_POWER_NAME_EMPTY_KEYWORD = MapError(41, 'POWER NAME IS EMPTY KEYWORD: %s')
MAP_POWER_NAME_CAN_BE_CONFUSED = MapError(42, 'POWER NAME CAN BE CONFUSED WITH LOCATION ALIAS OR ORDER TYPE: %s')
MAP_ILLEGAL_POWER_ABBREV = MapError(43, 'ILLEGAL POWER ABBREVIATION')
MAP_MISSING_ADJ = MapError(44, 'MISSING ADJACENCY: %s -> %s')

GAME_UNKNOWN_POWER = GameError(0, 'UNKNOWN POWER OR PLACENAME: %s')
GAME_UNKNOWN_UNIT_TYPE = GameError(1, 'UNKNOWN UNIT TYPE: %s')
GAME_UNKNOWN_LOCATION = GameError(2, 'UNKNOWN PLACENAME: %s')
GAME_UNKNOWN_COAST = GameError(3, 'UNKNOWN COAST: %s')
GAME_UNKNOWN_ORDER_TYPE = GameError(4, 'UNKNOWN ORDER TYPE: %s')
GAME_FORBIDDEN_RULE = GameError(5, 'RULE %s PREVENTS RULE %s FROM BEING APPLIED.')
GAME_UNRECOGNIZED_ORDER_DATA = GameError(6, 'UNRECOGNIZED DATA IN ORDER: %s')
GAME_AMBIGUOUS_PLACE_NAME = GameError(7, 'AMBIGUOUS PLACENAME: %s')
GAME_BAD_PHASE_NOT_IN_FLOW = GameError(8, 'BAD PHASE (NOT IN FLOW)')
GAME_BAD_BEGIN_PHASE = GameError(9, 'BAD BEGIN PHASE')
GAME_BAD_YEAR_GAME_PHASE = GameError(10, 'BAD YEAR IN GAME PHASE')
GAME_BAD_ADJUSTMENT_ORDER = GameError(11, 'BAD ADJUSTMENT ORDER: %s')
GAME_BAD_RETREAT = GameError(12, 'BAD RETREAT FOR %s: %s')
GAME_ORDER_TO_INVALID_UNIT = GameError(13, 'ORDER TO INVALID UNIT: %s')
GAME_ORDER_INCLUDES_INVALID_UNIT = GameError(14, 'ORDER INCLUDES INVALID UNIT: %s')
GAME_ORDER_INCLUDES_INVALID_DEST = GameError(15, 'ORDER INCLUDES INVALID UNIT DESTINATION %s')
GAME_ORDER_NON_EXISTENT_UNIT = GameError(16, 'ORDER TO NON-EXISTENT UNIT: %s')
GAME_ORDER_TO_FOREIGN_UNIT = GameError(17, 'ORDER TO FOREIGN UNIT: %s')
GAME_UNIT_MAY_ONLY_HOLD = GameError(18, 'UNIT MAY ONLY BE ORDERED TO HOLD: %s')
GAME_CONVOY_IMPROPER_UNIT = GameError(19, 'CONVOY ORDER FOR IMPROPER UNIT: %s %s')
GAME_INVALID_ORDER_NON_EXISTENT_UNIT = GameError(20, 'CANNOT %s NON-EXISTENT UNIT: %s %s')
GAME_INVALID_ORDER_RECIPIENT = GameError(21, 'INVALID %s RECIPIENT: %s %s')
GAME_BAD_ORDER_SYNTAX = GameError(22, 'BAD %s ORDER: %s %s')
GAME_ORDER_RECIPIENT_DOES_NOT_EXIST = GameError(23, '%s RECIPIENT DOES NOT EXIST: %s %s')
GAME_UNIT_CANT_SUPPORT_ITSELF = GameError(24, 'UNIT CANNOT SUPPORT ITSELF: %s %s')
GAME_UNIT_CANT_BE_CONVOYED = GameError(25, 'UNIT CANNOT BE CONVOYED: %s %s')
GAME_BAD_CONVOY_DESTINATION = GameError(26, 'BAD CONVOY DESTINATION: %s %s')
GAME_SUPPORTED_UNIT_CANT_REACH_DESTINATION = GameError(27, 'SUPPORTED UNIT CANNOT REACH DESTINATION: %s %s')
GAME_UNIT_CANT_PROVIDE_SUPPORT_TO_DEST = GameError(28, 'UNIT CANNOT PROVIDE SUPPORT TO DESTINATION: %s %s')
GAME_IMPROPER_CONVOY_ORDER = GameError(29, 'IMPROPER CONVOY ORDER: %s %s')
GAME_IMPROPER_SUPPORT_ORDER = GameError(30, 'IMPROPER SUPPORT ORDER: %s %s')
GAME_IMPOSSIBLE_CONVOY_ORDER = GameError(31, 'IMPOSSIBLE CONVOY ORDER: %s %s')
GAME_BAD_MOVE_ORDER = GameError(32, 'BAD MOVE ORDER: %s %s')
GAME_UNIT_CANT_CONVOY = GameError(33, 'UNIT CANNOT CONVOY: %s %s')
GAME_MOVING_UNIT_CANT_RETURN = GameError(34, 'MOVING UNIT MAY NOT RETURN: %s %s')
GAME_CONVOYING_UNIT_MUST_REACH_COST = GameError(35, 'CONVOYING UNIT MUST REACH COAST: %s %s')
GAME_ARMY_CANT_CONVOY_TO_COAST = GameError(36, 'ARMY CANNOT CONVOY TO SPECIFIC COAST: %s %s')
GAME_CONVOY_UNIT_USED_TWICE = GameError(37, 'CONVOYING UNIT USED TWICE IN SAME CONVOY: %s %s')
GAME_UNIT_CANT_MOVE_INTO_DEST = GameError(38, 'UNIT CANNOT MOVE INTO DESTINATION: %s %s')
GAME_UNIT_CANT_MOVE_VIA_CONVOY_INTO_DEST = GameError(39, 'UNIT CANNOT MOVE VIA CONVOY INTO DESTINATION: %s %s')
GAME_BAD_CONVOY_MOVE_ORDER = GameError(40, 'BAD CONVOY MOVE ORDER: %s %s')
GAME_CONVOY_THROUGH_NON_EXISTENT_UNIT = GameError(41, 'CONVOY THROUGH NON-EXISTENT UNIT: %s %s')
GAME_IMPOSSIBLE_CONVOY = GameError(42, 'IMPOSSIBLE CONVOY: %s %s')
GAME_INVALID_HOLD_ORDER = GameError(43, 'INVALID HOLD ORDER: %s %s')
GAME_UNRECOGNIZED_ORDER_TYPE = GameError(44, 'UNRECOGNIZED ORDER TYPE: %s %s')
GAME_INVALID_RETREAT = GameError(45, 'INVALID RETREAT: %s - %s')
GAME_NO_CONTROL_OVER = GameError(46, 'NO CONTROL OVER %s')
GAME_UNIT_NOT_IN_RETREAT = GameError(47, 'UNIT NOT IN RETREAT: %s')
GAME_TWO_ORDERS_FOR_RETREATING_UNIT = GameError(48, 'TWO ORDERS FOR RETREATING UNIT: %s')
GAME_INVALID_RETREAT_DEST = GameError(49, 'INVALID RETREAT DESTINATION: %s')
GAME_BAD_RETREAT_ORDER = GameError(50, 'BAD RETREAT ORDER: %s')
GAME_DATA_FOR_NON_POWER = GameError(51, 'DATA FOR NON-POWER: %s')
GAME_UNABLE_TO_FIND_RULES = GameError(52, 'UNABLE TO FIND FILE CONTAINING RULES.')
GAME_BUILDS_IN_ALL_ALT_SITES = GameError(53, 'BUILDS IN ALL ALTERNATIVE SITES (%s): %s')
GAME_NO_SUCH_UNIT = GameError(54, 'NO SUCH UNIT: %s')
GAME_MULTIPLE_ORDERS_FOR_UNIT = GameError(55, 'MULTIPLE ORDERS FOR UNIT: %s')
GAME_INVALID_BUILD_SITE = GameError(56, 'INVALID BUILD SITE: %s')
GAME_MULT_BUILDS_IN_SITE = GameError(57, 'MULTIPLE BUILDS IN SITE: %s')
GAME_INVALID_BUILD_ORDER = GameError(58, 'INVALID BUILD ORDER: %s')
GAME_NO_WAIVE_WITH_DISBAND = GameError(59, 'WAIVE NOT ALLOWED FOR DISBAND')
GAME_ORDER_NOT_ALLOWED = GameError(60, 'ORDER NOT ALLOWED: %s')

STD_GAME_BAD_ORDER = StdError(0, 'BAD ORDER: %s')
STD_GAME_UNIT_REORDERED = StdError(1, 'UNIT REORDERED: %s')
STD_GAME_UNORDERABLE_UNIT = StdError(2, 'UNORDERABLE UNIT: %s')
