# Ansii-Sequenzen
RESET =   chr(27)+"[m"
REVERSE = chr(27)+"[7m"
BLACK =   chr(27)+"[30m"
RED =     chr(27)+"[31m"
GREEN =   chr(27)+"[32m"
BROWN =   chr(27)+"[33m"
BLUE =    chr(27)+"[34m"
MAGENTA = chr(27)+"[35m"
CYAN =    chr(27)+"[36m"
WHITE =   chr(27)+"[37m"

# Fehler
ERRCODE = 255
ERRCHR = REVERSE + "?" + RESET


#   CHR: ASC1,ASC2,SCR1,SCR2
tab_chr2 = {
   # Ziffern u.a. (identische Codes)
   ' ': [  32,  32, 32, 32],
   '!': [  33,  33, 33, 33],
   '"': [  34,  34, 34, 34],
   '#': [  35,  35, 35, 35],
   '$': [  36,  36, 36, 36],
   '%': [  37,  37, 37, 37],
   '&': [  38,  38, 38, 38],
   '\'':[  39,  39, 39, 39],
   '(': [  40,  40, 40, 40],
   ')': [  41,  41, 41, 41],
   '*': [  42,  42, 42, 42],
   '+': [  43,  43, 43, 43],
   ',': [  44,  44, 44, 44],
   '-': [  45,  45, 45, 45],
   '.': [  46,  46, 46, 46],
   '/': [  47,  47, 47, 47],
   '0': [  48,  48, 48, 48],
   '1': [  49,  49, 49, 49],
   '2': [  50,  50, 50, 50],
   '3': [  51,  51, 51, 51],
   '4': [  52,  52, 52, 52],
   '5': [  53,  53, 53, 53],
   '6': [  54,  54, 54, 54],
   '7': [  55,  55, 55, 55],
   '8': [  56,  56, 56, 56],
   '9': [  57,  57, 57, 57],
   ':': [  58,  58, 58, 58],
   ';': [  59,  59, 59, 59],
   '<': [  60,  60, 60, 60],
   '=': [  61,  61, 61, 61],
   '>': [  62,  62, 62, 62],
   '?': [  63,  63, 63, 63],
   # AT-Zeichen
   '@': [  64,  64,  0,  0],
   # Grossbuchstaben
   'A': [  65,  97,  1, 65],
   'B': [  66,  98,  2, 66],
   'C': [  67,  99,  3, 67],
   'D': [  68, 100,  4, 68],
   'E': [  69, 101,  5, 69],
   'F': [  70, 102,  6, 70],
   'G': [  71, 103,  7, 71],
   'H': [  72, 104,  8, 72],
   'I': [  73, 105,  9, 73],
   'J': [  74, 106, 10, 74],
   'K': [  75, 107, 11, 75],
   'L': [  76, 108, 12, 76],
   'M': [  77, 109, 13, 77],
   'N': [  78, 110, 14, 78],
   'O': [  79, 111, 15, 79],
   'P': [  80, 112, 16, 80],
   'Q': [  81, 113, 17, 81],
   'R': [  82, 114, 18, 82],
   'S': [  83, 115, 19, 83],
   'T': [  84, 116, 20, 84],
   'U': [  85, 117, 21, 85],
   'V': [  86, 118, 22, 86],
   'W': [  87, 119, 23, 87],
   'X': [  88, 120, 24, 88],
   'Y': [  89, 121, 25, 89],
   'Z': [  90, 122, 26, 90],
   # weitere Zeichen (Pfund und Pfeil nach links fehlen)
   '[': [  91,  91, 27, 27],
   ']': [  93,  93, 29, 29],
   '^': [  94,  94, 30, 30],
   # Kleinbuchstaben (gibt es nur in Font 2)
   'a': [ None, 65, None,  1],
   'b': [ None, 66, None,  2],
   'c': [ None, 67, None,  3],
   'd': [ None, 68, None,  4],
   'e': [ None, 69, None,  5],
   'f': [ None, 70, None,  6],
   'g': [ None, 71, None,  7],
   'h': [ None, 72, None,  8],
   'i': [ None, 73, None,  9],
   'j': [ None, 74, None, 10],
   'k': [ None, 75, None, 11],
   'l': [ None, 76, None, 12],
   'm': [ None, 77, None, 13],
   'n': [ None, 78, None, 14],
   'o': [ None, 79, None, 15],
   'p': [ None, 80, None, 16],
   'q': [ None, 81, None, 17],
   'r': [ None, 82, None, 18],
   's': [ None, 83, None, 19],
   't': [ None, 84, None, 20],
   'u': [ None, 85, None, 21],
   'v': [ None, 86, None, 22],
   'w': [ None, 87, None, 23],
   'x': [ None, 88, None, 24],
   'y': [ None, 89, None, 25],
   'z': [ None, 90, None, 26],
}


#  SCR: CHR1,CHR2
tab_scr2 = {
   # AT-Zeichen
    0: [ '@', '@' ],
   # Grossbuchstaben bei Font 1
   # Kleinbuchstaben bei Font 2
    1: [ 'A', 'a' ],
    2: [ 'B', 'b' ],
    3: [ 'C', 'c' ],
    4: [ 'D', 'd' ],
    5: [ 'E', 'e' ],
    6: [ 'F', 'f' ],
    7: [ 'G', 'g' ],
    8: [ 'H', 'h' ],
    9: [ 'I', 'i' ],
   10: [ 'J', 'j' ],
   11: [ 'K', 'k' ],
   12: [ 'L', 'l' ],
   13: [ 'M', 'm' ],
   14: [ 'N', 'n' ],
   15: [ 'O', 'o' ],
   16: [ 'P', 'p' ],
   17: [ 'Q', 'q' ],
   18: [ 'R', 'r' ],
   19: [ 'S', 's' ],
   20: [ 'T', 't' ],
   21: [ 'U', 'u' ],
   22: [ 'V', 'v' ],
   23: [ 'W', 'w' ],
   24: [ 'X', 'x' ],
   25: [ 'Y', 'y' ],
   26: [ 'Z', 'z' ],
   # weitere Zeichen (Pfund und Pfeil nach links fehlen)
   27: [ '[', '[' ],
   28: [ None, None ],
   29: [ ']', ']' ],
   30: [ '^', '^' ],
   31: [ None, None ],
   # Ziffern u.a. (identische Codes)
   32: [ ' ', ' ' ],
   33: [ '!', '!' ],
   34: [ '"', '"' ],
   35: [ '#', '#' ],
   36: [ '$', '$' ],
   37: [ '%', '%' ],
   38: [ '&', '&' ],
   39: [ '\'', '\'' ],
   40: [ '(', '(' ],
   41: [ ')', ')' ],
   42: [ '*', '*' ],
   43: [ '+', '+' ],
   44: [ ',', ',' ],
   45: [ '-', '-' ],
   46: [ '.', '.' ],
   47: [ '/', '/' ],
   48: [ '0', '0' ],
   49: [ '1', '1' ],
   50: [ '2', '2' ],
   51: [ '3', '3' ],
   52: [ '4', '4' ],
   53: [ '5', '5' ],
   54: [ '6', '6' ],
   55: [ '7', '7' ],
   56: [ '8', '8' ],
   57: [ '9', '9' ],
   58: [ ':', ':' ],
   59: [ ';', ';' ],
   60: [ '<', '<' ],
   61: [ '=', '=' ],
   62: [ '>', '>' ],
   63: [ '?', '?' ],
   # horizontale Linie fehlt
   64: [ None, None ],
   # Grafikzeichen bei Font 1 fehlen
   # Grossbuchstaben bei Font 2
   65: [ None, 'A' ],
   66: [ None, 'B' ],
   67: [ None, 'C' ],
   68: [ None, 'D' ],
   69: [ None, 'E' ],
   70: [ None, 'F' ],
   71: [ None, 'G' ],
   72: [ None, 'H' ],
   73: [ None, 'I' ],
   74: [ None, 'J' ],
   75: [ None, 'K' ],
   76: [ None, 'L' ],
   77: [ None, 'M' ],
   78: [ None, 'N' ],
   79: [ None, 'O' ],
   80: [ None, 'P' ],
   81: [ None, 'Q' ],
   82: [ None, 'R' ],
   83: [ None, 'S' ],
   84: [ None, 'T' ],
   85: [ None, 'U' ],
   86: [ None, 'V' ],
   87: [ None, 'W' ],
   88: [ None, 'X' ],
   89: [ None, 'Y' ],
   90: [ None, 'Z' ],
}


#  ASC: CHR1,CHR2
tab_asc2 = {
   # Steuercodes
   5: [ WHITE, WHITE ],
   18: [ REVERSE, REVERSE ],
   28: [ RED, RED ],
   30: [ GREEN, GREEN ],
   31: [ BLUE, BLUE ],
   # Ziffern u.a. (identische Codes)
   32: [ ' ', ' ' ],
   33: [ '!', '!' ],
   34: [ '"', '"' ],
   35: [ '#', '#' ],
   36: [ '$', '$' ],
   37: [ '%', '%' ],
   38: [ '&', '&' ],
   39: [ '\'', '\'' ],
   40: [ '(', '(' ],
   41: [ ')', ')' ],
   42: [ '*', '*' ],
   43: [ '+', '+' ],
   44: [ ',', ',' ],
   45: [ '-', '-' ],
   46: [ '.', '.' ],
   47: [ '/', '/' ],
   48: [ '0', '0' ],
   49: [ '1', '1' ],
   50: [ '2', '2' ],
   51: [ '3', '3' ],
   52: [ '4', '4' ],
   53: [ '5', '5' ],
   54: [ '6', '6' ],
   55: [ '7', '7' ],
   56: [ '8', '8' ],
   57: [ '9', '9' ],
   58: [ ':', ':' ],
   59: [ ';', ';' ],
   60: [ '<', '<' ],
   61: [ '=', '=' ],
   62: [ '>', '>' ],
   63: [ '?', '?' ],
   # AT-Zeichen
   64: [ '@', '@' ],
   # Grossbuchstaben bei Font 1
   # Kleinbuchstaben bei Font 2
   65: [ 'A', 'a' ],
   66: [ 'B', 'b' ],
   67: [ 'C', 'c' ],
   68: [ 'D', 'd' ],
   69: [ 'E', 'e' ],
   70: [ 'F', 'f' ],
   71: [ 'G', 'g' ],
   72: [ 'H', 'h' ],
   73: [ 'I', 'i' ],
   74: [ 'J', 'j' ],
   75: [ 'K', 'k' ],
   76: [ 'L', 'l' ],
   77: [ 'M', 'm' ],
   78: [ 'N', 'n' ],
   79: [ 'O', 'o' ],
   80: [ 'P', 'p' ],
   81: [ 'Q', 'q' ],
   82: [ 'R', 'r' ],
   83: [ 'S', 's' ],
   84: [ 'T', 't' ],
   85: [ 'U', 'u' ],
   86: [ 'V', 'v' ],
   87: [ 'W', 'w' ],
   88: [ 'X', 'x' ],
   89: [ 'Y', 'y' ],
   90: [ 'Z', 'z' ],
   # weitere Zeichen (Pfund und Pfeil nach links fehlen)
   91: [ '[', '[' ],
   92: [ None, None ],
   93: [ ']', ']' ],
   94: [ '^', '^' ],
   95: [ None, None ],
   # horizontale Linie fehlt
   96: [ None, None ],
   # Grafikzeichen bei Font 1 fehlen
   # Grossbuchstaben bei Font 2
   97: [ None, 'A' ],
   98: [ None, 'B' ],
   99: [ None, 'C' ],
   100: [ None, 'D' ],
   101: [ None, 'E' ],
   102: [ None, 'F' ],
   103: [ None, 'G' ],
   104: [ None, 'H' ],
   105: [ None, 'I' ],
   106: [ None, 'J' ],
   107: [ None, 'K' ],
   108: [ None, 'L' ],
   109: [ None, 'M' ],
   110: [ None, 'N' ],
   111: [ None, 'O' ],
   112: [ None, 'P' ],
   113: [ None, 'Q' ],
   114: [ None, 'R' ],
   115: [ None, 'S' ],
   116: [ None, 'T' ],
   117: [ None, 'U' ],
   118: [ None, 'V' ],
   119: [ None, 'W' ],
   120: [ None, 'X' ],
   121: [ None, 'Y' ],
   122: [ None, 'Z' ],
   # Steuercodes
   144: [ BLACK, BLACK ],
   146: [ RESET, RESET ], # REVERSE OFF
   149: [ BROWN, BROWN ],
   156: [ MAGENTA, MAGENTA ], # PURPUR
   159: [ CYAN, CYAN ],
}


def chr2asc(ch, font):
   """ Gibt fuer das angegebene Zeichen den C64-ASCII
       Wert zurueck. Tritt ein Fehler auf, wird der Wert
       255 zurueck geliefert.
   """
   global tab_chr2, ERRCODE
   if font == 1:
       idx = 0
   elif font == 2:
       idx = 1
   else:
       raise ValueError("wrong font parameter")
   try:
       code = tab_chr2[ch][idx]
   except KeyError:
       code = ERRCODE
   if code is None:
       code = ERRCODE
   return code


def chr2scr(ch, font):
   """ Gibt fuer das angegebene Zeichen den C64-Bildschirmcode
       zurueck. Tritt ein Fehler auf, wird der Wert 255 zurueck
       geliefert.
   """
   global tab_chr2, ERRCODE
   if font == 1:
       idx = 2
   elif font == 2:
       idx = 3
   else:
       raise ValueError("wrong font parameter")
   try:
       code = tab_chr2[ch][idx]
   except KeyError:
       code = ERRCODE
   if code is None:
       code = ERRCODE
   return code


def scr2chr(code, font):
   """ Gibt fuer den angegebenen Bildschirmcode das Zeichen
       zurueck. Tritt ein Fehler auf, wird ein inverses
       Fragezeichen zurueck geliefert.
   """
   global tab_scr2, REVERSE, RESET, ERRCHR
   # Invertiertes Zeichen
   inv = (code >= 128)
   if inv:
       code = code & 127
   if font == 1:
       idx = 0
   elif font == 2:
       idx = 1
   else:
       raise ValueError("wrong font parameter")
   try:
       ch = tab_scr2[code][idx]
   except KeyError:
       ch = ERRCHR
   if ch is None:
       ch = ERRCHR
   if inv:
       return REVERSE + ch + RESET
   else:
       return ch


def asc2chr(code, font):
   """ Gibt fuer den angegebenen C64-ASCII Wert das Zeichen
       zurueck. Tritt ein Fehler auf, wird ein inverses
       Fragezeichen zurueck geliefert.
   """
   global tab_asc2, ERRCHR
   if font == 1:
       idx = 0
   elif font == 2:
       idx = 1
   else:
       raise ValueError("wrong font parameter")
   try:
       ch = tab_asc2[code][idx]
   except KeyError:
       ch = ERRCHR
   if ch is None:
       ch = ERRCHR
   return ch