from __future__ import print_function
import sys
from typing import List, Tuple, Any

def Chunker(seq: List[Any], size: int) -> List[List[Any]]:
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))

def ModToIndex(mods: List[Tuple[int]], m: int):
  try:
    return mods.index(m)
  except ValueError:
    mods.append(m)
    return len(mods)-1

def PrintMods(gid: str, mods: List[Tuple[int]]):
  L = [ "\t{ " + ", ".join( [ "%4d" % (round(128 * (val - 1)),) for val in m ] )  + " }" for m in mods ]
  print("static const PaletteMod paletteMods" + gid + "[] = {")
  print( ",\n".join(L) )
  print("};")

def PrintPic(gid: str, pics: List[List[int]], comments: List[str]):
  print("static const PicMod picMods" + gid + "[] = {")

  for comment in comments:
    print("\t// " + comment)

  for chunk in Chunker(pics, 5):
    t = ""
    for pic in chunk:
      t = t + "{ " + str(pic[0]).rjust(3, ' ') + ", " + str(pic[1]).rjust(2, ' ') + " }, "
    print("\t" + t)

  print("};")

def PrintView(gid: str, views: List[List[int]], comments: List[str]):
  print("static const ViewMod viewMods" + gid + "[] = {")

  for comment in comments:
    print("\t// " + comment)

  for chunk in Chunker(views, 5):
    t = ""
    for view in chunk:
      t = t + "{ " + str(view[0]).rjust(3, ' ') + ", " + str(view[1]).rjust(2, ' ') + ", " + str(view[2]).rjust(2, ' ') + ", " + str(view[3]).rjust(2, ' ') + " }, "
    print("\t" + t)

  print("};")

def ParseList(l: str) -> Tuple[str, List[str]]:
  assert(l[0] == '(')
  e = l.find(")")
  L = l[1:e].split(",")
  tests = []
  for t in L:
    t = t.strip()
    ell = t.find('..')
    if ell >= 0:
      start = int(t[0:ell])
      end = int(t[ell+2:])
      # interval
      for x in range(start, end + 1):
        tests.append(str(x))
    else:
      tests.append(t)
  return l[e+1:], tests

def ParseTriple(l: str) -> List[str]:
  assert(l[0] == '(')
  e = l.find(")")
  L = l[1:e].split(",")
  assert(len(L) == 3)
  return L

if __name__ == "__main__":
  if len(sys.argv) < 2:
    print("Usage: python scifx_to_header.py [scifx files] > scifx.cpp")
    sys.exit(-1)

  print("""
 /* ScummVM - Graphic Adventure Engine
  *
  * ScummVM is the legal property of its developers, whose names
  * are too numerous to list here. Please refer to the COPYRIGHT
  * file distributed with this source distribution.
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU 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 General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */

  // NB: This file is AUTO-GENERATED by devtools/sci/scifx/scifx_to_cpp.py
  // from devtools/sci/scifx/*.scifx

  #include "sci/graphics/helpers.h"
  #include "sci/graphics/screen.h"

  namespace Sci {
  """)
  input_files = sys.argv[1:]
  gids = []

  for F in input_files:
    comments = []
    pics = []
    views = []
    mods = [(1.,1.,1.)]
    gid = ""

    for l in open(F, "r").readlines():
      l = l.strip()
      if len(l) == 0:
        continue
      if l[0] == '#':
        comment = l[1:].strip()
        # Only add the top comments (before the game ID is set)
        if (gid == ""):
          comments.append(comment)
        continue
      if l[0:6] == "gameid":
        assert(gid == "")
        l = l[6:].strip()
        l = l.strip()
        assert(l[0] == "=")
        assert(l[-1] == ";")
        l = l[1:-1].strip()
        gid = l
        continue
      if l[0:4] == "view":
        ruletype = "view"
        l = l[4:]
      elif l[0:3] == "pic":
        ruletype = "pic"
        l = l[3:]
      else:
        assert(False)

      ids = []
      loops = [-1]
      cels = [-1]
      l,ids = ParseList(l)
      if l[0] == "(":
        l,loops = ParseList(l)
      if l[0] == "(":
        l,cels = ParseList(l)
      l = l.strip()
      assert(l[0:2] == "*=")
      assert(l[-1] == ";")
      l = l[2:-1].strip()
      if l[0] == "(":
        val = ParseTriple(l)
        val = (float(v) for v in val)
      else:
        val = (float(l), float(l), float(l))
      if ruletype == "pic":
        for pic in ids:
          pics.append([pic, ModToIndex(mods, val)])
      elif ruletype == "view":
        for view in ids:
          for loop in loops:
            for cel in cels:
              views.append([view, loop, cel, ModToIndex(mods, val)])

    if gid == "":
      raise ValueError("No gameid specified")

    gids.append(gid)

    PrintMods(gid, mods)
    print()
    PrintPic(gid, pics, comments)
    print()
    PrintView(gid, views, comments)
    print()

  print("static const SciFxMod mods[] = {")
  for gid in gids:
    print("\t{{ gid_{0}, paletteMods{0}, ARRAYSIZE(paletteMods{0}), picMods{0}, ARRAYSIZE(picMods{0}), viewMods{0}, ARRAYSIZE(viewMods{0}) }},".format(gid));
  print("};")

  print("""
  void setupCustomPaletteMods(GfxScreen *screen) {
    for (int i = 0; i < ARRAYSIZE(mods); i++) {
      if (mods[i].gameId == g_sci->getGameId()) {
        screen->setPaletteMods(mods[i].paletteMods, mods[i].paletteModsSize);
        break;
      }
    }
  }

  void doCustomViewPalette(GfxScreen *screen, GuiResourceId view, int16 loop, int16 cel) {
    for (int i = 0; i < ARRAYSIZE(mods); i++) {
      SciFxMod mod = mods[i];
      if (mod.gameId == g_sci->getGameId()) {
        for (int j = 0; j < mod.viewModsSize; j++) {
          ViewMod m = mod.viewMods[j];
          if (m.id == view && (m.loop == -1 || m.loop == loop) && (m.cel == -1 || m.cel == cel)) {
            screen->setCurPaletteMapValue(m.multiplier);
            break;
          }
        }
        break;
      }
    }
  }

  void doCustomPicPalette(GfxScreen *screen, GuiResourceId pic) {
    for (int i = 0; i < ARRAYSIZE(mods); i++) {
      SciFxMod mod = mods[i];
      if (mod.gameId == g_sci->getGameId()) {
        for (int j = 0; j < mod.picModsSize; j++) {
          PicMod m = mod.picMods[j];
          if (m.id == pic) {
            screen->setCurPaletteMapValue(m.multiplier);
            break;
          }
        }
        break;
      }
    }
  }

}""")
