// Hyperbolic Rogue -- quotient spaces
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details

/** \file quotient.cpp
 *  \brief quotient spaces
 */

#include "hyper.h"
namespace hr {

/** \brief quotient spaces */

EX namespace quotientspace {
  
  int cod(heptagon *h) {
    return zebra40(h->c7);
    }
  
  code get(heptspin hs) {
    code res;
    res.connections.resize(S7+1);
    res.connections[0] = cod(hs.at);
    for(int i=1; i<=S7; i++) {
      res.connections[i] = cod((hs + wstep).at);
      hs += 1;
      }
    return res;
    }
  
  EX int rvadd = 0;
  EX int rvdir = 1;
  
  int rv(int x) { return (rvadd+x*rvdir) % S7; }

#if HDR
constexpr int symmask = (1<<30);

struct code {
  vector<int> connections;

  bool operator == (const code &c2) const { return connections == c2.connections; }
  bool operator < (const code &c2) const { return connections < c2.connections; }

  };

struct hrmap_quotient : hrmap_standard {

  hrmap_hyperbolic base;
  
  vector<cell*> celllist;
  
  cell *origin;
  
  map<quotientspace::code, int> reachable;
  vector<heptspin> bfsq;
  
  vector<int> connections;
  
  void add(const heptspin& hs);

  vector<heptagon*> allh;

  void generate_connections();
  
  void build();
  
  explicit hrmap_quotient() {
    generate_connections();    
    build();
    }

  explicit hrmap_quotient(const vector<int>& con) : connections(con) {
    build();
    }

  heptagon *getOrigin() override { return allh[0]; }

  ~hrmap_quotient() {
    for(int i=0; i<isize(allh); i++) {
      clearHexes(allh[i]);
      tailored_delete(allh[i]);
      }
    }
  
  vector<cell*>& allcells() override { return celllist; }
  };
#endif
  
  void hrmap_quotient::add(const heptspin& hs) {
    code g = get(hs);
    if(!reachable.count(g)) {
      reachable[g] = bfsq.size();
      bfsq.push_back(hs);
      add(hs + 1);
      }
    }
  
  void hrmap_quotient::generate_connections() {
      
    dynamicval<hrmap*> cmap(currentmap, this);  
    connections.clear();
    switch(geometry) {
      #if CAP_FIELD
      case gFieldQuotient: {
        connections = currfp.connections;
        break;
        }
      #endif
        
      case gZebraQuotient: {
        heptspin hs(base.origin);
        reachable.clear();
        bfsq.clear();
        add(hs);
  
        for(int i=0; i<(int)bfsq.size(); i++) {
          hs = bfsq[i] + wstep;
          add(hs);
          connections.push_back(reachable[get(hs)]);
          }
        break;
        }
      
      case gMinimal: {
        int altzebra[6][7] = {  
          { 16,125,111, 45, 32, 56, 20 },
          { 26,102,146,152, 35,124, 00 },
          { 06, 55,143,134,115,101, 10 },
          { 41, 50, 04, 44,123, 14,153 },
          { 51, 30,154,122, 33, 03,112 },
          { 31, 40,113,136,142, 21, 05 }
          };
               
        // int ok = 0;
        for(int a=0; a<6; a++) {
        for(int b=0; b<7; b++) {
          int s = altzebra[a][b];
          int mirr = s/100; s %= 100;
          int which = s/10; s %= 10;
          
          int shouldbe = a*10+b+mirr*100;
          
          if(altzebra[which][s] != shouldbe) {
            printf("error at %d:%d (is=%d shouldbe=%d)\n", a, b, altzebra[which][s], shouldbe);
            }
          
          connections.push_back(which * 7 + s + (mirr ? symmask : 0) );
          }
          }
        break;
        }
      
      case gKleinQuartic: {
        connections = {
          /* 000 */ 7, 14, 21, 28, 35, 42, 49,
          /* 001 */ 0, 55, 56, 63, 70, 77, 15,
          /* 002 */ 1, 13, 83, 84, 91, 98, 22,
          /* 003 */ 2, 20, 104, 105, 112, 119, 29,
          /* 004 */ 3, 27, 125, 74, 126, 133, 36,
          /* 005 */ 4, 34, 139, 95, 66, 140, 43,
          /* 006 */ 5, 41, 146, 116, 87, 147, 50,
          /* 007 */ 6, 48, 153, 130, 108, 57, 8,
          /* 008 */ 9, 54, 107, 102, 154, 142, 64,
          /* 009 */ 10, 62, 141, 39, 94, 161, 71,
          /* 010 */ 11, 69, 167, 127, 31, 124, 78,
          /* 011 */ 12, 76, 123, 158, 149, 85, 16,
          /* 012 */ 17, 82, 148, 46, 115, 163, 92,
          /* 013 */ 18, 90, 162, 67, 38, 138, 99,
          /* 014 */ 19, 97, 137, 155, 59, 106, 23,
          /* 015 */ 24, 103, 58, 53, 129, 165, 113,
          /* 016 */ 25, 111, 164, 88, 45, 145, 120,
          /* 017 */ 26, 118, 144, 159, 79, 75, 30,
          /* 018 */ 32, 73, 166, 109, 52, 152, 134,
          /* 019 */ 33, 132, 151, 156, 100, 96, 37,
          /* 020 */ 40, 65, 61, 160, 121, 117, 44,
          /* 021 */ 47, 86, 81, 157, 135, 131, 51,
          /* 022 */ 60, 101, 136, 150, 80, 122, 143,
          /* 023 */ 68, 93, 89, 114, 110, 128, 72,
          };
        break;
        }
      
      case gBolza: {
        connections = {
          /* 000 */ 8, 16, 24, 32, 12, 20, 28, 36,
          /* 001 */ 0, 35, 47, 21, 4, 39, 43, 17,
          /* 002 */ 1, 15, 42, 29, 5, 11, 46, 25,
          /* 003 */ 2, 23, 45, 37, 6, 19, 41, 33,
          /* 004 */ 3, 31, 40, 9, 7, 27, 44, 13,
          /* 005 */ 34, 30, 18, 14, 38, 26, 22, 10,
          };
        break;
        }
      
      case gBolza2: {
        connections = {
/* 000 */ 16, 32, 48, 64, 24, 40, 56, 72,
/* 001 */ 20, 44, 52, 76, 28, 36, 60, 68,
/* 002 */ 0, 79, 83, 45, 8, 67, 95, 33,
/* 003 */ 4, 71, 87, 37, 12, 75, 91, 41,
/* 004 */ 1, 23, 94, 61, 13, 27, 86, 49,
/* 005 */ 5, 31, 90, 53, 9, 19, 82, 57,
/* 006 */ 2, 39, 85, 77, 10, 43, 89, 65,
/* 007 */ 6, 47, 81, 69, 14, 35, 93, 73,
/* 008 */ 3, 55, 88, 21, 15, 59, 80, 25,
/* 009 */ 7, 63, 92, 29, 11, 51, 84, 17,
/* 010 */ 70, 58, 46, 18, 78, 50, 38, 26,
/* 011 */ 66, 54, 42, 30, 74, 62, 34, 22,
          };
        break;
        }

      case gMacbeath: {
        connections = {
/* 000 */ 359, 498, 189, 215, 424, 381, 20, 
/* 001 */ 366, 491, 217, 187, 431, 346, 27, 
/* 002 */ 380, 484, 168, 208, 438, 360, 6, 
/* 003 */ 345, 477, 196, 180, 445, 367, 13, 
/* 004 */ 352, 470, 203, 173, 396, 388, 48, 
/* 005 */ 373, 463, 175, 201, 403, 339, 55, 
/* 006 */ 387, 456, 210, 194, 410, 353, 34, 
/* 007 */ 338, 449, 182, 222, 417, 374, 41, 
/* 008 */ 254, 459, 140, 138, 414, 248, 69, 
/* 009 */ 247, 480, 112, 166, 435, 255, 62, 
/* 010 */ 233, 452, 161, 117, 407, 269, 83, 
/* 011 */ 268, 487, 133, 145, 442, 234, 76, 
/* 012 */ 261, 473, 126, 152, 400, 241, 97, 
/* 013 */ 240, 494, 154, 124, 421, 262, 90, 
/* 014 */ 226, 466, 119, 159, 393, 276, 111, 
/* 015 */ 275, 501, 147, 131, 428, 227, 104, 
/* 016 */ 65, 479, 343, 355, 408, 73, 167, 
/* 017 */ 100, 465, 371, 383, 422, 94, 160, 
/* 018 */ 86, 472, 350, 348, 429, 108, 153, 
/* 019 */ 79, 486, 378, 376, 415, 59, 146, 
/* 020 */ 58, 458, 385, 369, 443, 80, 139, 
/* 021 */ 107, 500, 357, 341, 401, 87, 132, 
/* 022 */ 93, 493, 364, 390, 394, 101, 125, 
/* 023 */ 72, 451, 336, 362, 436, 66, 118, 
/* 024 */ 16, 483, 294, 313, 397, 31, 209, 
/* 025 */ 37, 462, 322, 285, 446, 24, 202, 
/* 026 */ 51, 448, 287, 334, 432, 10, 223, 
/* 027 */ 2, 497, 315, 306, 411, 45, 216, 
/* 028 */ 23, 476, 308, 299, 404, 38, 181, 
/* 029 */ 30, 469, 280, 327, 439, 17, 174, 
/* 030 */ 44, 455, 329, 292, 425, 3, 195, 
/* 031 */ 9, 490, 301, 320, 418, 52, 188, 
/* 032 */ 324, 467, 98, 110, 427, 332, 258, 
/* 033 */ 289, 453, 70, 82, 441, 283, 265, 
/* 034 */ 303, 495, 91, 89, 399, 297, 272, 
/* 035 */ 310, 481, 63, 61, 413, 318, 279, 
/* 036 */ 331, 460, 56, 68, 434, 325, 230, 
/* 037 */ 282, 474, 84, 96, 420, 290, 237, 
/* 038 */ 296, 488, 77, 75, 406, 304, 244, 
/* 039 */ 317, 502, 105, 103, 392, 311, 251, 
/* 040 */ 205, 475, 259, 236, 447, 178, 328, 
/* 041 */ 184, 454, 231, 264, 426, 213, 335, 
/* 042 */ 170, 489, 266, 243, 405, 199, 314, 
/* 043 */ 219, 496, 238, 271, 412, 192, 321, 
/* 044 */ 198, 482, 245, 278, 398, 171, 300, 
/* 045 */ 191, 503, 273, 250, 419, 220, 307, 
/* 046 */ 177, 468, 224, 257, 440, 206, 286, 
/* 047 */ 212, 461, 252, 229, 433, 185, 293, 
/* 048 */ 163, 450, 49, 40, 402, 150, 363, 
/* 049 */ 114, 478, 21, 12, 430, 129, 356, 
/* 050 */ 128, 471, 28, 47, 409, 115, 349, 
/* 051 */ 149, 499, 0, 19, 437, 164, 342, 
/* 052 */ 156, 492, 7, 26, 444, 143, 391, 
/* 053 */ 121, 464, 35, 54, 416, 136, 384, 
/* 054 */ 135, 485, 14, 5, 423, 122, 377, 
/* 055 */ 142, 457, 42, 33, 395, 157, 370, 
/* 056 */ 277, 102, 158, 389, 32, 172, 312, 
/* 057 */ 242, 88, 151, 340, 39, 200, 298, 
/* 058 */ 270, 74, 116, 354, 46, 193, 305, 
/* 059 */ 249, 60, 137, 375, 53, 221, 319, 
/* 060 */ 263, 95, 123, 382, 4, 214, 291, 
/* 061 */ 228, 109, 130, 347, 11, 186, 333, 
/* 062 */ 256, 67, 165, 361, 18, 207, 326, 
/* 063 */ 235, 81, 144, 368, 25, 179, 284, 
/* 064 */ 183, 50, 337, 162, 71, 232, 288, 
/* 065 */ 211, 43, 386, 141, 57, 253, 330, 
/* 066 */ 176, 36, 372, 120, 99, 225, 323, 
/* 067 */ 204, 29, 351, 127, 85, 260, 281, 
/* 068 */ 197, 22, 344, 113, 64, 246, 309, 
/* 069 */ 169, 15, 379, 134, 78, 267, 295, 
/* 070 */ 218, 8, 365, 155, 92, 239, 302, 
/* 071 */ 190, 1, 358, 148, 106, 274, 316, 
          };
        break;
        }
      
      case gBring: {
        connections = {
/* 000 */ 5, 92, 46, 33, 14, 
/* 001 */ 0, 62, 56, 38, 24, 
/* 002 */ 15, 97, 76, 63, 4, 
/* 003 */ 10, 32, 86, 68, 29, 
/* 004 */ 25, 67, 106, 93, 9, 
/* 005 */ 20, 37, 116, 98, 19, 
/* 006 */ 35, 102, 16, 3, 44, 
/* 007 */ 30, 72, 26, 8, 54, 
/* 008 */ 45, 107, 66, 73, 34, 
/* 009 */ 40, 2, 81, 78, 59, 
/* 010 */ 55, 77, 96, 103, 39, 
/* 011 */ 50, 7, 111, 108, 49, 
/* 012 */ 65, 112, 6, 13, 74, 
/* 013 */ 60, 42, 21, 18, 84, 
/* 014 */ 75, 117, 36, 43, 64, 
/* 015 */ 70, 12, 51, 48, 89, 
/* 016 */ 85, 47, 91, 113, 69, 
/* 017 */ 80, 17, 101, 118, 79, 
/* 018 */ 95, 82, 1, 23, 104, 
/* 019 */ 90, 52, 11, 28, 114, 
/* 020 */ 105, 87, 31, 53, 94, 
/* 021 */ 100, 22, 41, 58, 119, 
/* 022 */ 115, 57, 61, 83, 99, 
/* 023 */ 110, 27, 71, 88, 109,         
          };
        break;
        }

      case gHalfBring: {
        connections = {
          5, 12, 16, 23, 29,
          0, 32, 36, 43, 49,
          50, 41|symmask, 1, 48, 34|symmask,
          53|symmask, 2, 42|symmask, 45|symmask, 39,
          40, 31|symmask, 37|symmask, 3, 54|symmask,
          38|symmask, 52, 47|symmask, 33, 4,
          55, 21|symmask, 6, 28, 14|symmask,
          58|symmask, 7, 22|symmask, 25|symmask, 19,
          20, 11|symmask, 17|symmask, 8, 59|symmask,
          18|symmask, 57, 27|symmask, 13, 9,
          10, 56|symmask, 26, 15|symmask, 24|symmask,
          30, 51|symmask, 46, 35|symmask, 44|symmask
          };
        break;
        };

      case gSchmutzM2: {
        connections = {
          23,  47,  27,  14,  38,  30,  17,  41,  33,  20,  44,  24, 
          35,  39,   3,  26,  42,   6,  29,  45,   9,  32,  36,   0, 
          11,  43,  15,   2,  46,  18,   5,  37,  21,   8,  40,  12, 
          22,  31,   4,  13,  34,   7,  16,  25,  10,  19,  28,   1, 
          };
        break;
        }
      
      case gSchmutzM3: {
        connections = {
          23,  47,  64,  28,  15,  39,  68,  32,  19,  43,  60,  24, 
          35,  52,  40,   4,  27,  56,  44,   8,  31,  48,  36,   0, 
          11,  71,  57,  16,   3,  63,  49,  20,   7,  67,  53,  12, 
          22,  59,  69,   5,  14,  51,  61,   9,  18,  55,  65,   1, 
          21,  30,  62,  41,  13,  34,  66,  45,  17,  26,  70,  37, 
          10,  42,  50,  29,   2,  46,  54,  33,   6,  38,  58,  25, 
          };
        break;
        }
        
      default: break; 
      }
    }
    
  void hrmap_quotient::build() {

    dynamicval<hrmap*> cmap(currentmap, this);  

    int TOT = connections.size() / S7;
    // printf("heptagons = %d\n", TOT);
    // printf("all cells = %d\n", TOT*(S7+S3)/S3);
    if(!TOT) exit(1);
    allh.resize(TOT);
    for(int i=0; i<TOT; i++) allh[i] = init_heptagon(S7);
    // heptagon *oldorigin = origin;
    allh[0]->alt = base.origin;
  
    for(int i=0; i<TOT; i++) {
      heptagon *h = allh[i];
      if(true) {
        h->s = hsOrigin;
        h->fieldval = S7*i;
        if(!IRREGULAR) h->c7 = newCell(S7, h);
        }
      for(int j=0; j<S7; j++) {
        int co = connections[i*S7+j];
        bool swapped = co & symmask;
        co &= ~symmask;
        h->move(rv(j)) = allh[co/S7];
        h->c.setspin(rv(j), rv(co%S7), swapped);
        }
      }

    vector<heptagon*> by_dist;
    by_dist.push_back(allh[0]);
    for(int i=0; i<TOT; i++) {
      if(i >= isize(by_dist)) { printf("too fast\n"); exit(1); }
      for(int a=0; a<S7; a++) if(by_dist[i]->move(a)->alt == NULL) by_dist.push_back(by_dist[i]->move(a));
      currentmap->extend_altmap(by_dist[i], 0, false);
      }
  
    for(int i=0; i<TOT; i++) {
      allh[i]->emeraldval = allh[i]->alt->emeraldval;
      allh[i]->zebraval = allh[i]->alt->zebraval;
      allh[i]->fiftyval = allh[i]->alt->fiftyval;
      allh[i]->distance = allh[i]->alt->distance;
      /* for(int j=0; j<7; j++)
        allh[i]->move[j]->alt = createStep(allh[i]->alt, j); */
      }    
    
    #if CAP_IRR
    if(IRREGULAR) {
      irr::link_start(allh[0]);
      for(int i=0; i<TOT; i++)
        for(int j=0; j<S7; j++)
          irr::may_link_next(allh[i], j);
      }
    #endif

    celllister cl(gamestart(), 100, 100000000, NULL);
    celllist = cl.lst;
    }


EX struct hrmap_quotient* new_map() { return new hrmap_quotient; }

EX }


}