package puzzle;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.Accessors;
import static java.lang.Long.bitCount;
import static puzzle.SwedishGenerator.X;
//@formatter:on
@AllArgsConstructor
@Accessors(fluent = true)
public final class Clues {
   
   @Getter long lo, hi, vlo, vhi, rlo, rhi, xlo, xhi;
   public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0, 0, 0); }
   
   public Clues setClue(precomp.Const9x8.Cell cell) {
      if ((cell.index & 64) == 0) setClueLo(cell.mask, cell.d);
      else setClueHi(cell.mask, cell.d);
      return this;
   }
   
   public void setClueLo(long mask, byte idx) {
      lo |= mask;
      if ((idx & 1) != 0) vlo |= mask;
      else vlo &= ~mask;
      if ((idx & 2) != 0) rlo |= mask;
      else rlo &= ~mask;
      if ((idx & 4) != 0) xlo |= mask;
      else xlo &= ~mask;
   }
   public void setClueHi(long mask, byte idx) {
      hi |= mask;
      if ((idx & 1) != 0) vhi |= mask;
      else vhi &= ~mask;
      if ((idx & 2) != 0) rhi |= mask;
      else rhi &= ~mask;
      if ((idx & 4) != 0) xhi |= mask;
      else xhi &= ~mask;
   }
   public void clearClueLo(long mask) {
      lo &= mask;
      vlo &= mask;
      rlo &= mask;
      xlo &= mask;
   }
   public void clearClueHi(long mask) {
      hi &= mask;
      vhi &= mask;
      rhi &= mask;
      xhi &= mask;
   }
   public boolean isClueLo(int index) { return ((lo >>> index) & 1L) != X; }
   public boolean isClueHi(int index) { return ((hi >>> (index & 63)) & 1L) != X; }
   public boolean notClue(int index)  { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
   
   public int clueCount()             { return bitCount(lo) + bitCount(hi); }
   
   public Clues from(Clues best) {
      lo  = best.lo;
      hi  = best.hi;
      vlo = best.vlo;
      vhi = best.vhi;
      rlo = best.rlo;
      rhi = best.rhi;
      xlo = best.xlo;
      xhi = best.xhi;
      return this;
   }
   public byte getDir(int index) {
      if ((index & 64) == 0) {
         var v = (vlo & (1L << index)) != 0 ? 1 : 0;
         var r = (rlo & (1L << index)) != 0 ? 1 : 0;
         var x = (xlo & (1L << index)) != 0 ? 1 : 0;
         return (byte) ((x << 2) | (r << 1) | v);
      } else {
         var v = (vhi & (1L << (index & 63))) != 0 ? 1 : 0;
         var r = (rhi & (1L << (index & 63))) != 0 ? 1 : 0;
         var x = (xhi & (1L << (index & 63))) != 0 ? 1 : 0;
         return (byte) ((x << 2) | (r << 1) | v);
      }
   }
}
