// Copyrig 2021 - Unistra/CNRS
// The MOC API project is distributed under the terms
// of the GNU General Public License version 3.
//
//This file is part of MOC API java project.
//
//    MOC API java project 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, version 3 of the License.
//
//    MOC API java project 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.
//
//    The GNU General Public License is available in COPYING file
//    along with MOC API java project.
//
package cds.moc.misc;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Iterator;

import cds.moc.FMoc;
import cds.moc.Healpix;
import cds.moc.Moc;
import cds.moc.MocCell;
import cds.moc.SMoc;
import cds.moc.STMoc;
import cds.moc.TMoc;

public class MocTest {


   static String EXEMPLE = "12/9 12 "
         +"13/13-15 24 26-27 33 45 52 54 56-57 "
         +"14/39 45-47 49-51 102 122 141 143 176-177 179 188-189 232-233 236-237 240-242 "
         +"15/111 122-123 126-127 151 177 179 193-195 298-299 400 402-403 412 414-415 480 "
         +"482-483 492 494 560-561 563 569 660-661 663 712-713 715 740-741 743 761 764-765 "
         +"880 882 936-937 940-941 952-953 956 972 974 992-994 "
         +"16/430-431 441-443 483 486-487 498-499 502-503 599 603 615 621-623 705 707 "
         +"713-715 769-771 1208 1210-1211 1214-1215 1606 1624 1626-1627 1652 1654-1655 1832 "
         +"1834-1835 1924 1926-1927 1944 1946 1980 1982 2069 2071 2077 2079 2101 2249 2251 "
         +"2273 2284-2285 2287 2629 2649 2651 2676-2677 2679 2856-2857 2859 2948-2949 2951 "
         +"2969 3040-3041 3065 3068-3069 3400 3402 3424 3426 3432 3434 3552-3554 3560 3562 "
         +"3752-3753 3756-3757 3768-3769 3772-3773 3816-3817 3820-3821 3828-3829 3892 389 4"
         +"3904 3906 3980 3984";

   private static boolean testSetMocOrder() throws Exception {
      title("testSetMocOrder: Create a Moc manually, degrade the resolution step by step, and check the result...");
      long max,min;
      int order;

      System.out.println("SMOC testSetMocOrder");
      min = 1;
      max = SMoc.NBVAL_S/2L;
      SMoc moc1 = new SMoc("29/"+min+"-"+max);
      String ref1 = "0/0-5 4/1536";
      String s1=null;
      for( order=29; order>=0; order-=5) {
         moc1.setMocOrder(order);
         s1=moc1.toDebug();
         System.out.println("order: "+order+" -> "+s1+" range="+moc1.seeRangeList());
      }
      boolean rep=ref1.equals(moc1.toString());
      if( !rep ) System.out.println("MocTest.testSetMocOrder ERROR: \n.get ["+s1+"]\n.ref ["+ref1+"]\n");

      System.out.println("\nTMOC testSetMocOrder");
      min = 1;
      max = TMoc.NBVAL_T/2L;
      TMoc moc2 = new TMoc("61/"+min+"-"+max);
      String ref2 = "1/0 11/1024";
      String s2=null;
      for( order=61; order>=2; order-=10) {
         moc2.setMocOrder(order);
         s2=moc2.toDebug();
         System.out.println("order: "+order+" -> "+s2+" range="+moc2.seeRangeList());
      }
      rep&=ref2.equals(moc2.toString());
      if( !rep ) System.out.println("MocTest.testSetMocOrder ERROR TMOC: \n.get ["+s2+"]\n.ref ["+ref2+"]\n");

      System.out.println("\nSTMOC testSetMocOrder");
      min = 1L;
      max = Healpix.pow2(61)/12L;
      long mins = 1L;
      long maxs = Healpix.pow2(29)*Healpix.pow2(29);
      STMoc moc3 = new STMoc("t3/0-1 s3/1-3 t3/2 s3/2-5");
      String ref3 = "t1/0 s0/0";
      String s3=null;
      int sorder=3;
      for( order=61; order>=1; order-=20, sorder--) {
         moc3.setMocOrder(order, sorder);
         s3=moc3.toDebug();
         System.out.println("torder:"+order+",sorder="+sorder+" -> "+s3+" range="+moc3.seeRangeList());
      }
      rep&=ref3.equals(moc3.toString());
      if( !rep ) System.out.println("MocTest.testSetMocOrder ERROR TMOC: \n.get ["+s3+"]\n.ref ["+ref3+"]\n");

      if( rep ) System.out.println("MocTest.testSetMocOrder OK");
      return rep;
   }


   private static boolean testBasic() throws Exception {
      title("testBasic: Create a Moc manually and check the result...");
      String ref = " 3/1 3/3 3/10 4/16 4/17 4/18 4/22";
      SMoc moc = new SMoc();
      moc.add("3/10 4/12-15 18 22");
      moc.add("4/13-18 5/19 20");
      moc.add("3/1");
      Iterator<MocCell> it = moc.iterator();
      StringBuffer s = new StringBuffer();
      while( it.hasNext() ) {
         MocCell p = it.next();
         s.append(" "+p.order+"/"+p.start);
      }
      boolean rep = s.toString().equals(ref);
      if( !rep ) {
         System.out.println("MocTest.testBasic ERROR: \n.get ["+s+"]\n.ref ["+ref+"]\n");
         return false;
      }
      
      long nbCells=0L;
      Iterator<Long> it1 = moc.valIterator();
      while( it1.hasNext() ) { it1.next(); nbCells++; }
      System.out.println("\nNb used cells at MocOrder "+moc.getMocOrder()+" => "+ moc.getNbValues());
      rep = moc.getNbValues() == nbCells;
      if( !rep ) {
         System.out.println("Moc: "+moc);
         System.out.println("MocTest.testBasic ERROR: \n.nbCells get ["+moc.getNbCells()+"]\n.ref ["+nbCells+"]\n");
         return false;
      }
      
      
      if( rep ) System.out.println("MocTest.testBasic OK");
      return rep;
   }


   private static boolean testBasicTMoc() throws Exception {
      title("testBasic: Create a TMoc manually and check the result...");
      String ref = "t59/12 60/26";
      Moc moc = Moc.createMoc( ref );
      Iterator<MocCell> it = moc.iterator();
      StringBuffer s = new StringBuffer();
      while( it.hasNext() ) {
         MocCell p = it.next();
         if( s.length()>0 ) s.append(' ');
         else s.append('t');
         s.append(p.order+"/"+p.start);
      }
      boolean rep = s.toString().equals(ref);
      if( !rep ) {
         System.out.println("MocTest.testBasicTMoc ERROR: \n.get ["+s+"]\n.ref ["+ref+"]\n");
      } else System.out.println("MocTest.testBasicTMoc OK");
      return rep;
   }

   private static boolean testPerfMoc() throws Exception {
      title("testBasicSTMoc: intersectin perf");

      SMoc moc1 = new SMoc();
      moc1.read( "/Data/CDS-I-125A-catalog_MOC.fits");
      SMoc moc2 = new SMoc();
      moc2.read( "/Data/V_147_sdss12.moc.fits");
      SMoc moc3;
      for( int j=0; j<3; j++ ) {
         long t = System.currentTimeMillis();
         int n=10000;
         for( int i=0;i<n; i++ ) {
            moc3 = moc2.intersection(moc1);
         }
         long t1 = System.currentTimeMillis(); 
         System.out.println("intersection done in "+(double)(t1-t)/n+"ms");

      }
      return true;
   }

   private static boolean testAutoDetectionMoc() throws Exception {
      title("testAutoDetectionMoc: detects ASCII and Stream various MOCs");      
      String s1[] = {
            "t30/1-10 13-15 17 s3/1-2 5-8 t30/72-75 s5/200 t60/ s8/",
            "t30/1-10 13-15 17 31/",
            "3/1-2 5-8 8/"
      };
      for( String s : s1 ) {
         Moc moc1 = Moc.createMoc(s);
         System.out.println("\nAutodetection: "+s);
         System.out.println("ASCII detection : "+moc1.toDebug()+"\n => "+moc1);
         File f = File.createTempFile("moc", "tmp");
         moc1.write( new FileOutputStream(f));
         Moc moc2 = Moc.createMoc( new FileInputStream( f ));
         System.out.println("Stream detection: "+moc1.toDebug()+"\n => "+moc1);
         if( !moc1.equals(moc2) ) {
            System.out.println("MocTest.testAutoDetectionMoc ERROR");
            return false;
         }
      }

      System.out.println("MocTest.testAutoDetectionMoc OK");
      return true;
   }
   
   
   private static boolean writeSTMocJson() throws Exception {
      title("writeSTMocJson: Create a STMoc manually and check the result...");
      String ref = "t61/0 s29/0,1,2 t61/2 s28/0 t60/1 61/3 s29/2,5";
      STMoc moc = new STMoc();
      moc.add(ref);
      System.out.println("STMOC ASCII => "+moc);
      System.out.println("STMOC JSON  => "+moc.toJSON());
      return true;
   }


   private static boolean testBasicSTMoc() throws Exception {
      title("testBasicSTMoc: Create a STMoc manually and check the result...");
      String ref = "t28/1 29/1 4 7 30/1 10 13 17 s3/1-2 5-8 t28/18 s5/200";
      STMoc moc = new STMoc();
      moc.add("t30/1-10 13-15 17 s3/1 2 5-8 t28/18 s5/200");
      System.out.println("STMOC => "+moc);
      boolean rep = moc.toString().equals(ref);
      if( !rep ) {
         System.out.println("MocTest.testBasicSTMoc ERROR: \n.get ["+moc+"]\n.ref ["+ref+"]\n");
      } else System.out.println("MocTest.testBasicSTMoc OK");
      return rep;
   }

   private static boolean testCoverage() throws Exception {
      title("testCoverage: Create Mocs with various parts of the sky and check the results...");
      double fullMoc = (new SMoc( "0/0-11" )).getCoverage();
      double emptyMoc = (new SMoc( )).getCoverage();
      double partialMoc = (new SMoc( "0/0-3" )).getCoverage();
      boolean rep=true;
      if( fullMoc!=1. )      { System.out.println("MocTest.testCoverage ERROR: \n.get ["+fullMoc+"] should be 1"); rep &= false; } 
      if( emptyMoc!=0. )     { System.out.println("MocTest.testCoverage ERROR: \n.get ["+emptyMoc+"] should be 0"); rep &= false; } 
      if( partialMoc!=1./3 ) { System.out.println("MocTest.testCoverage ERROR: \n.get ["+partialMoc+"] should be 1/3"); rep &= false; } 

      if( rep ) System.out.println("MocTest.testCoverage OK");
      return rep;
   }

   private static boolean testSMocLimitOrder() throws Exception {
      title("testSMocLimitOrder: Test min and max limit order settings...");
      SMoc moc = (SMoc)Moc.createMoc("0/0 3/700 8/");
      String ref= "1/0-3 2/175";
      int mocOrder=2;

      System.out.println("MOC before: "+moc);
      moc.setMinOrder(1);
      moc.setMocOrder(2);
      System.out.println("MOC order [1..2]: "+moc);

      if( !moc.toString().equals(ref) ) {
         System.out.println("MocTest.testSMocLimitOrder ERROR\n");
         return false;
      }

      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testSMocLimitOrder ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }

      // Même test mais en ajoutant les pixels un par un
      moc = new SMoc();
      moc.setMinOrder(1);
      moc.setMocOrder(2);
      moc.add(0,0);
      moc.add(4,2810);
      if( !moc.toString().equals(ref) ) {
         System.out.println("MocTest.testSMocLimitOrder ERROR\n");
         return false;
      }

      System.out.println("testSMocLimitOrder OK");
      return true;
   }

   private static boolean testIterativeInsertion() throws Exception {
      int maxIns= 10000;
      title("testIterativeInsertion: Test various npix insertion methods ("+maxIns+" insertions)...");
      long t0=0,t1=0;
      SMoc moc,moc1;

      long max = SMoc.NBVAL_S-1L;
      long [] start = new long[maxIns];
      long [] end = new long[maxIns];
      for( int i=0; i<maxIns; i++ ) {
         long size = (long)(Math.random()*1000000L +1);
         if( size==0 ) size++;
         long val = (long)(Math.random()*(max-size));
         start[i] = val;
         end[i] = val+size;
      }

      // Insertion bas niveau sans buffer
      moc = new SMoc();
      // On le fait 3 fois pour que le JIT ait le temps de faire ce qu'il faut
      for( int j=0;j<3; j++ ) {
         moc.clear();
         t0=System.currentTimeMillis();
         for( int i=0; i<maxIns; i++ ) moc.add(SMoc.MAXORD_S,start[i],end[i]);
         t1=System.currentTimeMillis();
      }
      System.out.println(".insertion without buffer "+maxIns+" cells: "+(t1-t0)+"ms");
      System.out.println(".mem: "+ moc.getMem());

      // Insertion bas niveau avec buffer
      moc = new SMoc();
      moc.bufferOn();
      // On le fait 3 fois pour que le JIT ait le temps de faire ce qu'il faut
      for( int j=0;j<3; j++ ) {
         moc.clear();
         t0=System.currentTimeMillis();
         for( int i=0; i<maxIns; i++ ) moc.add(SMoc.MAXORD_S,start[i],end[i]);
         t1=System.currentTimeMillis();
      }
      moc.seeRangeList();  // Just to force the last flush()
      System.out.println(".insertion with buffer "+maxIns+" cells: "+(t1-t0)+"ms");
      System.out.println(".mem: "+ moc.getMem());

      // Test de la vitesse de determination du nb de cells hierarchique
      long nbCell;
      t0=System.currentTimeMillis();
      nbCell = moc.getNbCells();
      t1=System.currentTimeMillis();
      System.out.println(".nb hierarchy Cells "+nbCell+" cells: "+(t1-t0)+"ms");
      t0=System.currentTimeMillis();
      nbCell = moc.getNbCells();
      t1=System.currentTimeMillis();
      System.out.println(".nb hierarchy Cells (redo) "+nbCell+" cells: "+(t1-t0)+"ms");
      moc.add("29/123456789");
      t0=System.currentTimeMillis();
      nbCell = moc.getNbCells();
      t1=System.currentTimeMillis();
      System.out.println(".nb hierarchy Cells (after add) "+nbCell+" cells: "+(t1-t0)+"ms");

      // Insertion par lecture d'un MOC pre-existant en FITS
      File f = File.createTempFile("Moc", "fits");
      String filename = f.getAbsolutePath();
      moc.write(filename);
      moc1 = new SMoc();
      t0=System.currentTimeMillis();
      moc1.read(filename);
      t1=System.currentTimeMillis();
      System.out.println(".insertion from FITS file: "+(t1-t0)+"ms");
      f.delete();
      if( !moc.equals(moc1) ) {
         System.out.println("MocTest.testIterativeInsertion ERROR: inconsistency results D:\n.moc::"+moc.toDebug()+"\n.moc1:"+moc1.toDebug());
         return false;
      }

            // Insertion par lecture d'un MOC pré-existant en JSON
            f = File.createTempFile("Moc", "json");
            filename = f.getAbsolutePath();
            moc.writeJSON(filename);
            moc1 = new SMoc();
            t0=System.currentTimeMillis();
            moc1.read(filename);
            t1=System.currentTimeMillis();
            System.out.println(".insertion from JSON file: "+(t1-t0)+"ms");
            f.delete();
            if( !moc.equals(moc1) ) {
               System.out.println("MocTest.testIterativeInsertion ERROR: inconsistency results E:\n.moc::"+moc.toDebug()+"\n.moc1:"+moc1.toDebug());
               return false;
            }

      System.out.println("Moc result:"+moc.toDebug());

      System.out.println("testIterativeInsertion OK");
      return true;
   }


   private static boolean testIterativeInsertionTmoc() throws Exception {
      int maxIns= 100000;
      title("testIterativeInsertionTmoc: Test various npix insertion methods ("+maxIns+" insertions)...");
      long t0=0,t1=0;
      TMoc moc,moc1;

      long max = TMoc.NBVAL_T-1000000;
      long [] start = new long[maxIns];
      long [] end = new long[maxIns];
      for( int i=0; i<maxIns; i++ ) {
         long size = (long)(Math.random()*10000000L +1);
         if( size==0 ) size++;
         long val = (long)(Math.random()*(max-size));
         start[i] = val;
         end[i] = val+size;
      }

      // Insertion bas niveau
      moc = new TMoc();
      moc.bufferOn();
      for( int j=0;j<3; j++ ) {
         moc.clear();
         t0=System.currentTimeMillis();
         for( int i=0; i<maxIns; i++ ) moc.add(TMoc.MAXORD_T,start[i],end[i]);
         t1=System.currentTimeMillis();
      }
      System.out.println(".insertion "+maxIns+" cells: "+(t1-t0)+"ms");

      // Insertion par lecture d'un MOC pre-existant en FITS
      File f = File.createTempFile("Moc", "fits");
      String filename = f.getAbsolutePath();
      moc.write(filename);
      moc1 = new TMoc();
      t0=System.currentTimeMillis();
      moc1.read(filename);
      t1=System.currentTimeMillis();
      System.out.println(".insertion from FITS file: "+(t1-t0)+"ms");
      f.delete();
      if( !moc.equals(moc1) ) {
         System.out.println("MocTest.testIterativeInsertionTmoc ERROR: inconsistency results D:\n.moc::"+moc.toDebug()+"\n.moc1:"+moc1.toDebug());
         return false;
      }

      // Insertion par lecture d'un MOC pré-existant en JSON
      f = File.createTempFile("Moc", "json");
      filename = f.getAbsolutePath();
      moc.writeJSON(filename);
      moc1 = new TMoc();
      t0=System.currentTimeMillis();
      moc1.read(filename);
      t1=System.currentTimeMillis();
      System.out.println(".insertion from JSON file: "+(t1-t0)+"ms");
      f.delete();
      if( !moc.equals(moc1) ) {
         System.out.println("MocTest.testIterativeInsertionTmoc ERROR: inconsistency results E:\n.moc::"+moc.toDebug()+"\n.moc1:"+moc1.toDebug());
         return false;
      }

      System.out.println("Moc result:"+moc.toDebug());

      System.out.println("testIterativeInsertionTmoc OK");
      return true;
   }


   private static boolean testContains() throws Exception {
      title("testContains: Create a Moc manually and check contains() methods...");
      Healpix hpx = new Healpix();
      SMoc moc = new SMoc("2/0 3/10 4/35");
      System.out.println("MOC: "+moc);
      boolean rep=true;
      try {
         System.out.println("- contains(028.93342,+18.18931) [asserting IN]    => "+moc.contains(hpx,028.93342,18.18931)); rep &= moc.contains(hpx,028.93342,18.18931);
         System.out.println("- contains(057.23564,+15.34922) [asserting OUT]   => "+moc.contains(hpx,057.23564,15.34922)); rep &= !moc.contains(hpx,057.23564,15.34922);
         System.out.println("- contains(031.89266,+17.07820) [asserting IN]    => "+moc.contains(hpx,031.89266,17.07820)); rep &= moc.contains(hpx,031.89266,17.07820);
      } catch( Exception e ) {
         e.printStackTrace();
         rep=false;
      }
      if( !rep ) System.out.println("MocTest.testContains ERROR:");
      else System.out.println("MocTest.testContains OK");
      return rep;
   }

   private static boolean testFITSTMoc() throws Exception {
      title("testFITSTMoc: Create a TMOC manually, write it in FITS and re-read it...");
      TMoc moc = new TMoc();
      moc.add("32/2-4 35/");
      String mocS="31/1 32/4 35/";
      int mocOrder = 35;

      String file = "/Users/Pierre/Desktop/__TMOC.fits";
      System.out.println("- MOC created: "+moc);
      moc.writeFITS(file);
      System.out.println("- test write (FITS) seems OK");

      StringBuilder trace = new StringBuilder();
      FileInputStream in = new FileInputStream(file);
      int rep = MocLint.checkFits(trace,in);
      in.close();
      if( rep==1 ) System.out.println("- test read (FITS) OK and IVOA valid");
      else if( rep==-1 ) System.out.println("- test read (FITS) WARNING, MOC ok but IVOA unvalid");
      if( rep!=1 ) System.out.println(trace);
      if( rep==0 ) {
         System.out.println("MocTest.testFITS ERROR: not IVOA valid");
         return false;
      }

      moc = new TMoc();
      moc.read(file);
      System.out.println("- MOC re-read: "+moc);
      if( !moc.toString().equals(mocS) ) {
         System.out.println("MocTest.testFITSTMoc ERROR: waiting=["+mocS+"]");
         return false;
      }
      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testFITSTMoc ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }

      System.out.println("testFITSTMoc OK");
      return true;
   }



   private static boolean testFITS() throws Exception {
      title("testFITS: Create a MOC manually, write it in FITS and re-read it...");
      SMoc moc = new SMoc();
      moc.add("3/10 4/12-15 18 22");
      moc.add("4/13-18 5/19-20");
      moc.add("17/222 28/123456789 29/");
      String mocS="3/3 10 4/16-18 22 5/19-20 17/222 28/123456789 29/";
      int mocOrder = 29;

      String testProp = "BigValue";
      moc.setProperty("MYKEY", testProp,"A test for a key");
      try { moc.setProperty("MOCTOOL", "MyTool","An alternate Tools"); } catch( Exception e) {}

      String file = "/Users/Pierre/Desktop/__MOC.fits";
      System.out.println("- MOC created: "+moc);
      moc.writeFITS(file);
      System.out.println("- test write (FITS) seems OK");

      StringBuilder trace = new StringBuilder();
      FileInputStream in = new FileInputStream(file);
      int rep = MocLint.checkFits(trace,in);
      in.close();
      if( rep==1 ) System.out.println("- test read (FITS) OK and IVOA valid");
      else if( rep==-1 ) System.out.println("- test read (FITS) WARNING, MOC ok but IVOA unvalid");
      if( rep!=1 ) System.out.println(trace);
      if( rep==0 ) {
         System.out.println("MocTest.testFITS ERROR: not IVOA valid");
         return false;
      }

      moc = new SMoc();
      moc.read(file);
      System.out.println("- MOC re-read: "+moc);

      if( !moc.toString().equals(mocS) ) {
         System.out.println("MocTest.testFITS ERROR: waiting=["+mocS+"]");
         return false;
      }
      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testFITS ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }
      System.out.println("MYKEY: "+moc.getProperty("MYKEY"));
      System.out.println("MOCTOOL: "+moc.getProperty("MOCTOOL"));
      if( !testProp.equals(moc.getProperty("MYKEY")) ) {
         System.out.println("MocTest.testFITS ERROR: wrong property: MYKEY should be equals to "+testProp+ "=> ["+moc.getProperty("MYKEY")+"]");
         return false;
      }

      System.out.println("testFITS OK");
      return true;
   }

   private static boolean testFITSSTMoc() throws Exception {
      title("testFITSSTMoc: Create a STMOC manually, write it in FITS and re-read it...");
      STMoc moc = new STMoc("t61/1 3 5 s3/1-3 t61/50 52 s4/25");
      String mocS="t61/1 3 5 s3/1-3 t61/50 52 s4/25";

      String file = "/Users/Pierre/Desktop/__STMOC.fits";
      System.out.println("- MOC created: "+moc);
      moc.writeFITS(file);
      System.out.println("- test write (FITS) seems OK");

      StringBuilder trace = new StringBuilder();
      FileInputStream in = new FileInputStream(file);
      int rep = MocLint.checkFits(trace,in);
      in.close();
      if( rep==1 ) System.out.println("- test read (FITS) OK and IVOA valid");
      else if( rep==-1 ) System.out.println("- test read (FITS) WARNING, MOC ok but IVOA unvalid");
      if( rep!=1 ) System.out.println(trace);
      if( rep==0 ) {
         System.out.println("MocTest.testFITS ERROR: not IVOA valid");
         return false;
      }

      moc = new STMoc();
      moc.read(file);
      System.out.println("- MOC re-read: "+moc);
      if( !moc.toString().equals(mocS) ) {
         System.out.println("MocTest.testFITSSTMoc ERROR: waiting=["+mocS+"]");
         return false;
      }

      System.out.println("testFITSSTMoc OK");
      return true;
   }


   private static boolean testJSON() throws Exception {
      title("testJSON: Create a MOC manually, write it in JSON and re-read it...");
      
      STMoc moc1=new STMoc();
      String ascii = "t32/4 8 s8/3 77 t29/3 31/18 s3/1-4 t34/ s8/";
      String json = "[  { \"t\":{ \"32\":[4,8]}, \"s\":{ \"8\":[3,77]} },  "
            + "{ \"t\":{ \"29\":[3],\"31\":[18]}, \"s\":{ \"3\":[1,2,3,4]} },   "
            + "{ \"t\":{ \"34\":[] }, \"s\":{ \"8\":[] } } ]";
      
      moc1.add(json);
      System.out.println(" STMOC ASCII: "+moc1);
      System.out.println(" STMOC JSON:"+moc1.toJSON());
      if( !moc1.toString().equals(ascii) ) {
         System.out.println("MocTest.testJSON ERROR: wrong stmoc JSON parsing. Waiting "+ascii);
         return false;
      }
      if( !moc1.toJSON().equals(json) ) {
         System.out.println("MocTest.testJSON ERROR: wrong stmoc JSON writing. Waiting "+json);
         return false;
      }
      
      SMoc moc = new SMoc();
      moc.add("3/10 4/12-15 18 22");
      moc.add("4/13-18 5/19-20");
      moc.add("17/222 28/123456789 29/");
      String mocS="3/3 10 4/16-18 22 5/19-20 17/222 28/123456789 29/";
      int mocOrder = 29;

      String file = "/Users/Pierre/Desktop/__MOC.json";
      System.out.println("- MOC created: "+moc);
      moc.writeJSON(file);
      System.out.println("- test write (JSON) seems OK");

      moc = new SMoc();
      moc.read(file);
      System.out.println("- MOC re-read: "+moc);
      if( !moc.toString().equals(mocS) ) {
         System.out.println("MocTest.testJSON ERROR: waiting=["+mocS+"]");
         return false;
      }
      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testJSON ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }
      
      System.out.println("testJSON OK");
      return true;
   }

   private static boolean testASCII() throws Exception {
      title("testASCII: read ASCII format...");
      String s = 
            "3/3,10 4/16,17,18,22 5/19,20\n" +
                  "17/222 28/123456789\n";
      int mocOrder = 28;
      InputStream stream = new ByteArrayInputStream(s.getBytes());

      String mocS="3/3 10 4/16-18 22 5/19-20 17/222 28/123456789";

      SMoc moc = new SMoc();
      moc.read(stream);
      System.out.println("- MOC read: "+moc);
      if( !moc.toString().equals(mocS) ) {
         System.out.println("MocTest.testASCII ERROR: waiting=["+mocS+"]");
         return false;
      }
      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testASCII ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }

      System.out.println("testASCII OK");
      return true;
   }

   private static boolean testSTRING() throws Exception {
      title("testASCII: read STRING format...");
      String s = "3/3 10 4/16-18 22 5/19-20 17/222 28/";
      int mocOrder = 28;
      InputStream stream = new ByteArrayInputStream(s.getBytes());

      SMoc moc = new SMoc();
      moc.read(stream);
      System.out.println("- MOC read: "+moc);
      if( !moc.toString().equals(s) ) {
         System.out.println("MocTest.testSTRING ERROR: waiting=["+s+"]");
         return false;
      }
      if( moc.getMocOrder()!=mocOrder ) {
         System.out.println("MocTest.testSTRING ERROR: wrong mocOrder "+moc.getMocOrder()+" waiting "+mocOrder);
         return false;
      }

      System.out.println("testSTRING OK");
      return true;
   }

   private static boolean testOperation() throws Exception {
      title("testOperation: Create 2 Mocs manually, test intersection(), union(), equals(), clone()...");
      SMoc moc1 = (SMoc)Moc.createMoc("3/1,3-4,9 4/30-31");
      String moc1S = "3/1 3-4 9 4/30-31";
      System.out.println("- Loading moc1: "+moc1);
      if( !moc1.toString().equals(moc1S) ) {
         System.out.println("MocTest.testOperation load ERROR: waiting=["+moc1S+"]");
         return false;
      }

      SMoc moc2 = (SMoc)Moc.createMoc("4/23 3/3 10 4/23-28;4/29 5/65");
      String moc2S = "3/3 6 10 4/23 28-29 5/65";
      System.out.println("- Loading moc2: "+moc2);
      if( !moc2.toString().equals(moc2S) ) {
         System.out.println("MocTest.testOperation load ERROR: waiting=["+moc2S+"]");
         return false;
      }

      SMoc moc3 =  moc2.clone();
      System.out.println("- Cloning moc2->moc3: "+moc3);
      if( !moc3.toString().equals(moc2S) ) {
         System.out.println("MocTest.testOperation clone ERROR: waiting=["+moc2S+"]");
         return false;
      }

      Moc moc4 = moc2.intersection(moc1);
      String moc4S = "3/3 5/65";
      System.out.println("- Intersection moc2 moc1: "+moc4);
      if( !moc4.toString().equals(moc4S) ) {
         System.out.println("MocTest.testOperation intersection ERROR: waiting=["+moc4S+"]");
         return false;
      }
      if( !moc1.intersection(moc2).toString().equals(moc4S) ) {
         System.out.println("MocTest.testOperation intersection ERROR: no commutative");
         return false;
      }

      Moc moc5 = moc3.union(moc1);
      String moc5S = "3/1 3-4 6-7 9-10 4/23 5/";
      System.out.println("- Union moc3 moc1: "+moc5);
      Moc moc5b = moc1.union(moc3);
      System.out.println("- Union moc1 moc3: "+moc5b);
      if( !moc5b.toString().equals(moc5.toString()) ) {
         System.out.println("MocTest.testOperation union ERROR: no commutative (get: "+moc5b+")");
         return false;
      }
      if( !moc5.toString().equals(moc5S) ) {
         System.out.println("MocTest.testOperation union ERROR: waiting=["+moc5S+"]");
         return false;
      }

      Moc moc7 = moc1.subtraction(moc2);
      String moc7S = "3/1 9 4/17-19 30-31 5/64 66-67";
      System.out.println("- Subtraction moc1 - moc2: "+moc7);
      if( !moc7.toString().equals(moc7S) ) {
         System.out.println("MocTest.testOperation subtraction ERROR: waiting=["+moc7S+"]");
         return false;
      }

      String moc6S="3/3 6 10 4/23 28 29";
      SMoc moc6 = new SMoc(moc6S);
      boolean test=moc6.equals(moc2);
      System.out.println("- Not-equals moc2 ["+moc6S+"] : "+test);
      if( test ) {
         System.out.println("MocTest.testOperation equals ERROR: waiting=[false]");
         return false;
      }
      moc6.add("5:65");
      test=moc6.equals(moc2);
      System.out.println("- Equals moc2 ["+moc2S+"] : "+test);
      if( !test ) {
         System.out.println("MocTest.testOperation equals ERROR: waiting=[true]");
         return false;
      }

      Moc moc8 = moc1.difference(moc2);
      String moc8S = "3/1 6-7 9-10 4/17-19 23 5/64 66-67";
      System.out.println("- difference moc1  moc2: "+moc8);
      if( !moc8.toString().equals(moc8S) ) {
         System.out.println("MocTest.testOperation difference ERROR: waiting=["+moc8S+"]");
         return false;
      }
      if( !moc1.difference(moc2).toString().equals(moc8S) ) {
         System.out.println("MocTest.testOperation difference ERROR: no commutative");
         return false;
      }


      System.out.println("testOperation OK");
      return true;
   }

   private static boolean testComplement() throws Exception {
      title("testComplement: Create 2 Mocs manually, and test isIntersecting() in both directions...");

      SMoc moc10=new SMoc("0/2-11 1/1-3");
      Moc moc9 = moc10.complement();
      String moc9S = "0/1 1/0";
      System.out.println("- SMoc       : "+moc10);
      System.out.println("    Complement: "+moc9);
      if( !moc9.toString().equals(moc9S) ) {
         System.out.println("MocTest.testComplement SMOC ERROR: waiting=["+moc9S+"]");
         return false;
      }

      TMoc moc8=new TMoc("1/0 2/3-4");
      Moc moc7 = moc8.complement();
      String moc7S = "2/2";
      System.out.println("- TMoc       : "+moc8);
      System.out.println("    Complement: "+moc7);
      if( !moc7.toString().equals(moc7S) ) {
         System.out.println("MocTest.testComplement TMOC ERROR: waiting=["+moc7S+"]");
         return false;
      }

      STMoc moc6=new STMoc("t1/1 s0/0-10");
      Moc moc5 = moc6.complement();
      String moc5S = "t1/0 s0/0-11 t1/1 s0/11";
      System.out.println("- STMoc       : "+moc6);
      System.out.println("    Complement: "+moc5);
      if( !moc5.toString().equals(moc5S) ) {
         System.out.println("MocTest.testComplement STMOCERROR: waiting=["+moc5S+"]");
         return false;
      }

      System.out.println("testComplement OK");
      return true;
   }



   private static boolean testIsIntersecting() throws Exception {
      title("testIsIntersecting: Create 2 Mocs manually, and test isIntersecting() in both directions...");
      SMoc moc1 = new SMoc("11/25952612");
      SMoc moc2 = new SMoc("9/1622036,1622038");
      System.out.println("moc1="+moc1);
      System.out.println("moc2="+moc2);
      boolean rep1=moc2.isIntersecting(moc1);
      boolean rep2=moc1.isIntersecting(moc2);
      System.out.println("moc2 inter moc1 = "+rep1);
      System.out.println("moc1 inter moc2 = "+rep2);
      if( !rep1 || !rep2 ) {
         System.out.println("MocTest.isIntersecting ERROR");
         return false;
      }

      System.out.println("isIntersecting OK");
      return true;
   }

   private static boolean testisIncluding() throws Exception {
      title("testisIncluding: Create 2 Mocs manually, and test isContaining() in both directions...");
      SMoc moc1 = new SMoc("11/25952612");
      SMoc moc2 = new SMoc("9/1622036,1622038");
      System.out.println("moc1="+moc1);
      System.out.println("moc2="+moc2);
      boolean rep1=moc2.isIncluding(moc1);
      boolean rep2=moc1.isIncluding(moc2);
      System.out.println("moc1 is included in moc2 = "+rep1);
      System.out.println("moc2 is included in moc1 = "+rep2);
      if( !rep1 || rep2 ) {
         System.out.println("MocTest.isIncluding ERROR");
         return false;
      }

      System.out.println("isIncluding OK");
      return true;
   }

   private static boolean testisEmptyOrFull() throws Exception {
      title("testisEmptyOrFull: Check isEmpty and isFull...");

      SMoc moc1 = new SMoc();
      boolean rep1 = moc1.isEmpty();
      if( !rep1 ) System.out.println("SMoc should be empty");
      moc1.add("0/0-11 29/");
      boolean rep2 = moc1.isFull();
      if( !rep2 ) System.out.println("SMoc should be full");
      moc1 = moc1.subtraction( Moc.createMoc("3/1"));
      boolean rep3 = !moc1.isEmpty() && !moc1.isFull();
      if( !rep3 ) System.out.println("SMoc should be not empty nor full");
      if( !rep1 || !rep2 || !rep3 ) {
         System.out.println("MocTest.testisEmptyOrFull SMOC ERROR");
         return false;
      }

      TMoc moc2 = new TMoc();
      rep1 = moc2.isEmpty();
      if( !rep1 ) System.out.println("TMoc should be empty");
      moc2.add("0/0 61/");
      rep2 = moc2.isFull();
      if( !rep2 ) System.out.println("TMoc should be full");
      moc2 = moc2.subtraction( Moc.createMoc("t31/1"));
      rep3 = !moc2.isEmpty() && !moc2.isFull();
      if( !rep3 ) System.out.println("TMoc should be not empty nor full");
      if( !rep1 || !rep2 || !rep3 ) {
         System.out.println("MocTest.testisEmptyOrFull TMOC ERROR");
         return false;
      }

      STMoc moc3 = new STMoc();
      rep1 = moc3.isEmpty();
      if( !rep1 ) System.out.println("STMoc should be empty");
      moc3.add("t0/0 s0/0-11");
      rep2 = moc3.isFull();
      if( !rep3 ) System.out.println("STMoc should be full");
      moc3 = moc3.subtraction( Moc.createMoc("t31/1 s3/11"));
      rep3 = !moc3.isEmpty() && !moc3.isFull();
      if( !rep3 ) System.out.println("STMoc should be not empty nor full");
      if( !rep1 || !rep2 || !rep3 ) {
         System.out.println("MocTest.testisEmptyOrFull STMOC ERROR");
         return false;
      }

      System.out.println("isEmptyOrFull OK");
      return true;
   }

   private static boolean testSTMocExtraction() throws Exception {
      title("testSTMocExtraction: create a STMoc, and extract SMoc and TMoc from it...");

      STMoc moc = (STMoc)Moc.createMoc("t61/3-10 s3/0-2 t61/13-20 s4/81 83");
      System.out.println("STMOC: "+moc);

      SMoc smoc = moc.getSpaceMoc();
      TMoc tmoc = moc.getTimeMoc();
      System.out.println("TMOC : "+tmoc);
      System.out.println("SMOC : "+smoc);

      String s1 = "59/1 4 60/4 7 61/3 10 13 20";
      if( !tmoc.toString().equals(s1) ) {
         System.out.println("MocTest.testSTMocExtraction TMOC ERROR: should be => "+s1);
         return false;
      }

      String s2 = "3/0-2 4/81 83";
      if( !smoc.toString().equals(s2) ) {
         System.out.println("MocTest.testSTMocExtraction SMOC ERROR: should be => "+s2);
         return false;
      }

      System.out.println("testSTMocExtraction OK");
      return true;
   }


   private static boolean  testSpeedSTMoc() throws Exception {
      STMoc moc = new STMoc();
      STMoc moc1 = new STMoc();
      long t0,t1;
      String u,id;
      InputStream in;
      
      t0 = System.currentTimeMillis();
//      id="CDS/B/assocdata/obscore";
      id="CDS/B/chandra/chandra";
      u="http://alasky.cds.unistra.fr/MocServer/query?"+id+"&get=anymoc";
      System.out.println("Loading "+id+" STMOC from CDS MocServer ["+u+"]...");
      in = new URL(u).openStream();
      moc.read(in);
      t1 = System.currentTimeMillis();
      System.out.println("STMoc download & read: "+(t1-t0)+"ms => "+moc.toDebug());

      int N=1000;
      TMoc tmoc=null;
      for( int i=0; i<3; i++ ) {
         t0 = System.currentTimeMillis();
         for( int j=0; j<N; j++ ) tmoc = moc.getTimeMoc();
         t1 = System.currentTimeMillis();
      }
      System.out.println("TMoc extraction: "+(t1-t0)/(double)N+"ms => "+tmoc.toDebug());

      N=20;
      SMoc smoc=null;
      for( int i=0; i<3; i++ ) {
         t0 = System.currentTimeMillis();
         for( int j=0; j<N; j++ ) smoc = moc.getSpaceMoc();
         t1 = System.currentTimeMillis();
      }
      System.out.println("SMoc extraction: "+(t1-t0)/(double)N+"ms => "+smoc.toDebug());
      
      t0 = System.currentTimeMillis();
//      id="CDS/B/vsx/vsx";
      id="CDS/B/xmm/xmmlog";
      u="http://alasky.cds.unistra.fr/MocServer/query?"+id+"&get=anymoc";
      System.out.println("Loading "+id+" STMOC from CDS MocServer ["+u+"]...");
      in = new URL(u).openStream();
      moc1.read(in);
      t1 = System.currentTimeMillis();
      System.out.println("STMoc download & read: "+(t1-t0)+"ms => "+moc1.toDebug());
      
      N=2;
      STMoc union=null;
      for( int i=0; i<3; i++ ) {
         t0 = System.currentTimeMillis();
         for( int j=0; j<N; j++ ) union = moc.union(moc1);
         t1 = System.currentTimeMillis();
      }
      System.out.println("STMoc union: "+(t1-t0)/(double)N+"ms => "+union.toDebug());

      N=20;
      STMoc inter=null;
      for( int i=0; i<3; i++ ) {
         t0 = System.currentTimeMillis();
         for( int j=0; j<N; j++ ) inter = moc.intersection(moc1);
         t1 = System.currentTimeMillis();
      }
      System.out.println("STMoc intersection: "+(t1-t0)/(double)N+"ms => "+inter.toDebug());

      return true;

   }

   private static boolean testDegrade() throws Exception {
      STMoc moc = new STMoc();
      long t0,t1;
      t0 = System.currentTimeMillis();
      moc.read("C:\\Users\\Pierre\\Documents\\Fits et XML\\MocImg\\PanSTARRs stmoc.fits");
      t1 = System.currentTimeMillis();
      System.out.println("STMoc read: "+(t1-t0)+"ms => "+moc.toDebug());

      System.out.println("Before:  "+moc.toDebug());
      int i=0;
      while( moc.getMem()>100L*1024L ) {
         i++;
         long max = (int)( 2L*(moc.getMem()/3L) ); 
         moc.reduction( max );
         System.out.println("Step "+i+": "+ moc.toDebug());
      }
      return true;
   }


   private static boolean testRange() throws Exception {
      title("testRange: Create a Mocs manually, and test setMin and Max limitOrder()...");
      SMoc moc1 = (SMoc) Moc.createMoc("{ \"1\":[0,1], \"2\":[8,9], \"3\":[40,53] }");
      System.out.println("moc1="+moc1);
      moc1.add("3/37 53");
      System.out.println("adding 3/37 53 => "+moc1);
      String s1 = "1/0-1 2/8-9 3/40 53";
      if( !moc1.toString().equals(s1) ) {
         System.out.println("MocTest.testRange add() ERROR: waiting=["+s1+"]");
         return false;
      }

      SMoc moc2 = moc1.clone();
      moc2.setMinOrder(2);
      System.out.println("minOrder2 => "+moc2);
      String s2 = "2/0-9 3/40 53";
      if( !moc2.toString().equals(s2) ) {
         System.out.println("MocTest.testRange setMinOrder(2) ERROR: waiting=["+s2+"]");
         return false;
      }

      SMoc moc3 = moc1.clone();
      moc3.setMocOrder(2);
      System.out.println("mocOrder3 => "+moc3);
      String s3 = "1/0-1 2/8-10 13";
      if( !moc3.toString().equals(s3) ) {
         System.out.println("MocTest.testRange setMocOrder(2) ERROR: waiting=["+s3+"]");
         return false;
      }

      moc3.setMinOrder(1);
      boolean in1 = moc3.isIncluding(0, 1);
      if( in1 ) {
         System.out.println("MocTest.testRange isIncluding(0,1) ERROR: waiting=false]");
         return false;
      }
      boolean in2 = moc3.isIncluding(1, 1);
      if( !in2 ) {
         System.out.println("MocTest.testRange isIncluding(0,0) ERROR: waiting=true]");
         return false;
      }
      boolean in3 = moc3.isIncluding(3, 33);
      if( !in3 ) {
         System.out.println("MocTest.testRange isIncluding(3,33) ERROR: waiting=true]");
         return false;
      }
      boolean in5 = moc3.isIncluding(3, 56);
      if( in5 ) {
         System.out.println("MocTest.testRange isIncluding(3,56) ERROR: waiting=false]");
         return false;
      }

      System.out.println("testRange OK");
      return true;
   }

   private static boolean testIteratorSTMoc() throws Exception {
      title("testIteratorSTMoc: Test on MOC iterators...");
      String s1 = "t30/1-6 8 s1/3-4 t29/20 s2/8 t31/ s3/";
      String ref = "\n t31/2-13 => s1/3-4\n t31/16-17 => s1/3-4\n t31/80-83 => s2/8";
      STMoc moc = new STMoc();
      moc.add(s1);
      System.out.println(".Loading : "+s1);
      System.out.println(".Getting : "+moc);

      // Iterator order per order
      Iterator<MocCell> it = moc.iterator();
      StringBuilder s = new StringBuilder();
      while( it.hasNext() ) {
         MocCell p = it.next();
         s.append("\n t"+p.order+"/"+p.start+(p.end-1!=p.start?"-"+(p.end-1):"")+" => s"+p.moc);
      }
      boolean rep = s.toString().equals(ref);
      if( !rep ) {
         System.out.println("MocTest.testIteratorSTMoc [iterator()] ERROR:\n.get ["+s+"]\n.ref ["+ref+"]\n");
         return false;
      }

      System.out.println("testIteratorSTMoc OK");
      return true;
   }

   private static boolean testInclusive() throws Exception {
      title("MocTest: Test isIncluding()...");
      String ref = "2/1 4/33";
      SMoc moc = new SMoc( ref );
      System.out.println(".moc="+moc);

      SMoc reg1 = new SMoc("3/5,6");
      boolean in1 = moc.isIncluding( reg1 );
      System.out.println(".reg1="+reg1+" is included ? => "+in1);
      if( !in1 ) {
         System.out.println("MocTest.testInclusive ERROR: should be true]");
         return false;
      }
      SMoc reg2 = new SMoc("3/5,8");
      boolean in2 = moc.isIncluding( reg2 );
      System.out.println(".reg2="+reg2+" is included ? => "+in2);
      if( in2 ) {
         System.out.println("MocTest.testInclusive ERROR: should be false]");
         return false;
      }

      SMoc reg3 = new SMoc("4/33");
      boolean in3 = moc.isIncluding( reg3 );
      System.out.println(".reg3="+reg3+" is included ? => "+in3);
      if( !in3 ) {
         System.out.println("MocTest.testInclusive ERROR: should be true]");
         return false;
      }

      SMoc reg4 = new SMoc("4/34");
      boolean in4 = moc.isIncluding( reg4 );
      System.out.println(".reg4="+reg4+" is included ? => "+in4);
      if( in4 ) {
         System.out.println("MocTest.testInclusive ERROR: should be false]");
         return false;
      }

      System.out.println("testInclusive OK");
      return true;

   }

   private static boolean testSyscompatibility() throws Exception {
      title("MocTest: Test testSyscompatibility()...");
      SMoc moc = new SMoc("3/1-2");
      moc.setSpaceSys("G");
      SMoc moc1 = new SMoc("3/3-4");
      boolean ok=true;
      try { 
         Moc m = moc.union(moc1);
         ok=false;
      } catch( Exception e ) {
         System.out.println("testSyscompatibility: Get exception => ok ["+e.getMessage()+"]");
      }
      if( ok ) System.out.println("testSyscompatibility Ok");
      else System.out.println("testSyscompatibility ERROR: should return exception");
      return ok;
   }

   private static boolean testHashCode() throws Exception {
      title("MocTest: Test testHashCode()...");
      String s1="t60/1-67 s3/1-2 t61/ s4/";
      String s2="t60/1-67 61/5 s3/1-2 4/4";
      STMoc moc1 = new STMoc(s1);
      STMoc moc2 = new STMoc(s2);
      System.out.println("moc1="+moc1);
      System.out.println("moc2="+moc2);
      System.out.println("Equals = "+moc1.equals(moc2));
      int hash1 = moc1.hashCode();
      int hash2 = moc2.hashCode();
      System.out.println("hash1="+hash1);
      System.out.println("hash2="+hash2);
      boolean ok = hash2==hash1;
      if( ok ) System.out.println("testHashCode Ok");
      else System.out.println("testHashCode ERROR: hashcodes should be equal");
      return ok;
   }


   static final private String TEST[][] = {
         { "Ajout à vide",                              "",           "t61/5-10 s29/2",   "t60/3-4 61/5 10 s29/2" ,             ""},
         { "Ajout singleton derrière singleton",        "t61/4 s29/1",       "t61/5 s29/2",      "t61/4 s29/1 t61/5 s29/2",            ""},
         { "Ajout singleton avant singleton",           "t61/5 s29/2",       "t61/4 s29/1",      "t61/4 s29/1 t61/5 s29/2",            ""},
         { "Ajout intervalle entrelacés après",         "t61/4-6 s29/1",     "t61/5-8 s29/2",    "t61/4 s29/1 t61/5-6 s29/1-2 t61/7-8 s29/2", ""},
         { "Ajout intervalle entrelacés avant",         "t61/5-8 s29/2",     "t61/4-6 s29/1",    "t61/4 s29/1 t61/5-6 s29/1-2 t61/7-8 s29/2", ""},
         { "Ajout intervalle englobant (s différents)", "t61/2-6 s29/2",     "t61/1-8 s29/1",    "t61/1 s29/1 t60/1-2 61/6 s29/1-2 t61/7-8 s29/1", ""},
         { "Ajout intervalle englobant (s identiques)", "t61/2-6 s29/2",     "t61/1-8 s29/2",    "t59/1 60/1 61/1 8 s29/2",               "t60/1-2 61/6 s29/2"},
         { "Ajout intervalle interne (s différents)",   "t61/1-8 s29/1",     "t61/2-6 s29/2",    "t61/1 s29/1 t60/1-2 61/6 s29/1-2 t61/7-8 s29/1", ""},
         { "Ajout intervalle interne (s identiques)",   "t61/1-8 s29/2",     "t61/2-6 s29/2",    "t59/1 60/1 61/1 8 s29/2" ,              "t60/1-2 61/6 s29/2"},         
         { "Intercallage",                              "t61/6-7 11 s29/1",  "t61/9 s29/2",      "t60/3 s29/1 t61/9 s29/2 t61/11 s29/1",    ""},         
         { "Fusion différents s",                       "t61/2-6 8-9 s29/2", "t61/7 s29/1",      "t60/1-2 61/6 s29/2 t61/7 s29/1 t60/4 s29/2",   ""},         
         { "Fusion indentiques s",                      "t61/2-6 8-9 s29/2", "t61/7 s29/2",      "t59/1 60/1 4 s29/2 t61/ s29/",               ""},         
         { "Remplacement sur début",                    "t61/2-6 s29/2 t61/7 s29/1", "t61/2-7 s29/2",   "t60/1-2 61/6 s29/2 t61/7 s29/1-2",        "t60/1-2 61/6 s29/2"},         
         { "Remplacement sur fin",                      "t61/3-7 s29/2 t61/8 s29/1", "t61/2-7 s29/2",   "t59/1 60/1 s29/2 t61/8 s29/1",          "t59/1 61/3 s29/2"},         
         { "Remplacement sur fin2",                     "t61/2-4 s29/2 t61/6 s29/1", "t61/6 s29/2",     "t60/1 61/4 s29/2 t61/6 s29/1-2",        ""},         
         { "Tordu",                                     "t61/3 s29/1 t61/4-5 s29/2", "t61/3-5 s29/3",   "t61/3 s29/1 3 t60/2 s29/2-3",      ""},         
         { "Inter simple",                              "t61/3-5 s29/1-3",    "t61/4-8 s29/2-4", "t61/3 s29/1-3 t60/2 s29/1-4 t60/3 61/8 s29/2-4",  "t60/2 s29/2-3 t61/ s29/"},         
         { "Inter spécial",     "t61/1 s29/1-6 t61/3-9 s29/2","t61/3 s29/5-7 t61/8 s29/1-2", "t61/1 s29/1-6 t61/3 s29/2 5-7 t59/1 s29/2 t61/8 s29/1-2 t61/9 s29/2","t61/8 s29/2" },         
         { "Ajout en suite",                            "t61/1-4 s29/1",      "t61/5-6 s29/1",   "t60/1-2 61/1 6 s29/1",               "" }
   };

   private static boolean testOperationSTMoc() throws Exception { return testOperationSTMoc(-1); }
   private static boolean testOperationSTMoc(int x) throws Exception {
      title("MocTest: Test testOperationSTMoc()...");
      String listTest[][] = x== -1 ? TEST : new String[][]{ TEST[x] };
      StringBuilder s = new StringBuilder();

      try {
         int i= x==-1 ? 0 : x;
         for( String [] test : listTest ) {
            STMoc stmoc1 = new STMoc(test[1]);
            STMoc stmoc2 = new STMoc(test[2]);
            s.append("\n"+(i++)+") "+test[0]+":");
            s.append("\n A: "+stmoc1+"\n B: "+stmoc2);

            STMoc stmoc4 = stmoc1.intersection( stmoc2);
            s.append("\n Inter: "+stmoc4);
            s.append( test[4].equals(stmoc4.toString()) ? " => OK" : " => ERROR waiting: "+test[4] );

            STMoc stmoc3 = stmoc1.union( stmoc2);
            s.append("\n Union: "+stmoc3);
            s.append( test[3].equals(stmoc3.toString()) ? " => OK" : " => ERROR waiting: "+test[3] );

            STMoc stmoc5 = stmoc1.subtraction( stmoc2);
            s.append("\n subtraction A-B: "+stmoc5);
            STMoc stmoc51 = stmoc2.subtraction( stmoc1);
            s.append("\n subtraction B-A: "+stmoc51);

            STMoc stmoc6 = (STMoc) stmoc1.difference( stmoc2);
            s.append("\n difference: "+stmoc6);
            STMoc stmoc7 = stmoc3.subtraction( stmoc4 );
            s.append( stmoc7.toString().equals( stmoc6.toString() ) ? " => OK" : " => ERROR waiting: "+stmoc7.toString() );

            //               for( int j=0; j<stmoc2.range.sz; j+=2 ) {
            //                  stmoc1.range.add(stmoc2.range.r[j], stmoc2.range.r[j+1], stmoc2.range.rr[j/2]);
            //               }
            //               s.append("\n Add  : "+stmoc1);
            //               s.append( test[3].equals(stmoc1.toString()) ? " => OK" : " => ERROR waiting: "+test[3] );

            s.append("\n");
         }
      } catch( Exception e ) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      System.out.println(s);
      boolean res = s.indexOf("ERROR")<0;
      if( res ) System.out.println("testOperationSTMoc OK");
      else System.out.println("testOperationSTMoc ERROR");
      return res;
   }

   
   private static boolean testBug() throws Exception {
      boolean res=true;
      title("MocTest: Test testBug()...");
      SMoc moc = new SMoc("1/1");
      moc.setMinOrder(3);
      moc.setMinOrder(0);
      try {
         moc.write("C:/Data/Moc.fits");
      } catch( Exception e ) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      if( res ) System.out.println("testBug OK");
      else System.out.println("testBug ERROR");
      return res;
   }


   private static void title(String s) {
      StringBuffer s1 = new StringBuffer(100);
      s1.append('\n');
      for( int i=0; i<20; i++ ) s1.append('-');
      s1.append(" "+s+" ");
      for( int i=0; i<20; i++ ) s1.append('-');
      System.out.println(s1);
   }

   class Source {
      double ra,de,rad;
      Source(double ra,double de,double rad) {
         this.ra=ra; this.de=de; this.rad=rad;
      }
   }
   
   
   static void testFMoc() throws Exception {
      FMoc fmoc = new FMoc();
      double freq;
      for( long i=0; i<63; i++ ) {
         freq = fmoc.getFreq(5, i);
         System.out.println(i+" -> "+freq);
      }
      
      double f1,f2,f3;
      long v1 = fmoc.getHash(f1=5.048709793414476e-29);
      long v2 = fmoc.getHash(f2=5.048709793414477e-29);
      long v3 = fmoc.getHash(f3=5.048709793414478e-29);
      System.out.println("v1="+v1+" v2="+v2+" v3="+v3+ " freq="+f1+" delta="+(f3-f2));

      v1 = fmoc.getHash(f1=5.846006549323609e+48);
      v2 = fmoc.getHash(f2=5.846006549323610e+48);
      v3 = fmoc.getHash(f3=5.846006549323611e+48);
      System.out.println("v1="+v1+" v2="+v2+" v3="+v3+ " freq="+f1+" delta="+(f3-f2));
      
      double GH=1000000000.;
      f1=44*GH;  //44GHz
      v1 = fmoc.getHash(f1);
      v2= v1+1;
      f2 = fmoc.getFreq(FMoc.MAXORD_F, v2);
      System.out.println(FMoc.MAXORD_F+": f1="+f1+"("+f1/GH+") v1="+v1+" f2="+f2+"("+f2/GH+") v2="+v2+" delta="+(f2-f1));
      
      for( int i = FMoc.MAXORD_F-1; i>=0; i-- ) {
         v1=v1/2;
         f1=fmoc.getFreq(i, v1);
         v2=v1+1;
         f2 = fmoc.getFreq(i, v2);
         System.out.println(i+": f1="+f1+"("+f1/GH+") v1="+v1+" f2="+f2+"("+f2/GH+") v2="+v2+" delta="+(f2-f1));
      }

//      System.out.println("Resolution à FOrder max...");
//      long v = 1;
//      while( v<FMoc.LMAX ) {
//         freq = fmoc.getFreq(FMoc.MAXORD_F,v);
//         double freq1 = fmoc.getFreq(FMoc.MAXORD_F,v+1);
//         System.out.println("v="+FMoc.MAXORD_F+"/"+v+" => freq="+freq+" res="+(freq1-freq));
//         v<<=10;
//      }
      
      fmoc.add("5/0,2,4");
      System.out.println("fmoc = "+fmoc);
   }
   
   static void testFMocViaMocServer() throws Exception {
      FMoc fmoc = new FMoc();
      double LS = 299297456200.;
      
      URL url = new URL("http://alasky.u-strasbg.fr/MocServer/query?ID=*/P/*&fields=ID,em_*");
      BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream()));
      
      String id=null;
      double freqMin=Double.NaN;
      double freqMax=Double.NaN;
      
      String line;
      while( (line=r.readLine())!=null ) {
         int a = line.indexOf('=');
         if( a!=-1 ) {
            String key = line.substring(0,a).trim();
            String val = line.substring(a+1).trim();
            if( key.equals("em_min") ) freqMax=LS/Double.parseDouble(val);
            else if( key.equals("em_max") ) freqMin=LS/Double.parseDouble(val);
            else if( key.equals("ID") ) id=val;
         }
         if( line.trim().length()==0) {
            if( id!=null ) {
               System.out.println("je dois ajouter "+freqMin+".."+freqMax+" ("+id+")");
               if( freqMin>freqMax ) {
                  System.out.println("  permutation");
                  double x=freqMin; freqMin=freqMax; freqMax=x;
               }
               if( !Double.isNaN(freqMin) && !Double.isNaN(freqMax) ) fmoc.add(freqMin, freqMax);
            }
            id=null;
            freqMin=freqMax=Double.NaN;
         }
      }
      r.close();
      System.out.println("FMOC = "+fmoc);
   }
   
   
   static void testSplit() throws Exception {
      Healpix hpx = new Healpix();
//      SMoc smoc = new SMoc("3/4,5,12 4/13,15 8/");
      SMoc smoc = new SMoc();
      smoc.read("/Data/MOCHST.fits");
//      smoc.read("/Data/GALEXMOC.fits");

      System.out.println("Moc initial: "+smoc.toDebug());
      long t=System.currentTimeMillis();
      SMoc [] sm = smoc.split(hpx,true);
      t = System.currentTimeMillis() - t;
      System.out.println("# independent components :"+sm.length+" in "+t+"ms");
//      for( SMoc m : sm ) System.out.println("- MOC: "+m.toDebug());
   }

   // Juste pour tester
   public static void main(String[] args) {
      boolean ok=true;

      try {
         Moc.setMocOrderLogic( Moc.LOGIC_MAX );
         
//         testFMoc();
//         testFMocViaMocServer();
         
         
        testSplit(); 
        if( true ) System.exit(0);
         

//          SMOC
         ok&=testBasic();
         ok&=testOperation(); 
         ok&=testSyscompatibility();
         ok&=testIsIntersecting();
         ok&=testisIncluding(); 
         ok&=testInclusive();
         ok&=testRange();
         ok&=testContains();
         ok&=testCoverage();
         ok&=testisEmptyOrFull();
         ok&=testSMocLimitOrder();
         ok&=testSetMocOrder();
         ok&=testIterativeInsertion();
         
         // ADVANCED
         ok&=testComplement();
         ok&=testAutoDetectionMoc();

         // TMOC
         ok&=testBasicTMoc();
         ok&=testIterativeInsertionTmoc();

         // STMOC
         ok&=testBasicSTMoc();
         ok&=testIteratorSTMoc();
         ok&=testOperationSTMoc();
         ok&=testSTMocExtraction();
         ok&=testHashCode();
         

         // FITS
         ok&=testFITS();
         ok&=testFITSTMoc();
         ok&=testFITSSTMoc();

         // ASCII
         ok&=testJSON();
         ok&=testASCII();
         ok&=testSTRING();
         
         // Others
//         ok&=testPerfMoc();
//         ok&=testDegrade();
//         ok&=testSpeedSTMoc();
//         ok&=writeSTMocJson();
//         ok&=testBug();



         if( ok ) System.out.println("-------------- All is fine  -----------");
         else System.out.println("-------------- There is a problem  -----------");
      } catch( Exception e ) {
         e.printStackTrace();
      }
   }



}
