package org.yaz4j;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.yaz4j.exception.ZoomException;
import org.yaz4j.jni.SWIGTYPE_p_ZOOM_record_p;
import org.yaz4j.jni.SWIGTYPE_p_p_ZOOM_record_p;
import org.yaz4j.jni.SWIGTYPE_p_ZOOM_resultset_p;
import org.yaz4j.jni.yaz4jlib;

/**
 * This class represents a "buffered handle" to the result set created on the
 * server and thus retrieving records may invlove a request to the server if
 * those records are not locally cached. Details on how to configure the retrieval
 * (present) process are available in the YAZ manual
 *
 * @see <a href="http://www.indexdata.com/yaz/doc/zoom.resultsets.html">YAZ ZOOM result sets</a>
 *
 * Becacuse of the server misbehaviour or errors during retrieval the
 * "getRecord" method may either return null or throw exceptions, even when the
 * index of retrieved records lies within the bounds of the set. Client
 * code should be prepared for such situations.
 *
 * This class implements the iterable interface and as such can be used within
 * foreach loops, it's important to note however that in this case the errors
 * during retrieval will be masked with standard NoSuchElementExceptions
 *
 * @author jakub
 */
public class ResultSet implements Iterable<Record> {
  //for GC refcount

  private Connection conn;
  private SWIGTYPE_p_ZOOM_resultset_p resultSet;
  private long size = 0;
  private boolean disposed = false;

  ResultSet(SWIGTYPE_p_ZOOM_resultset_p resultSet, Connection conn) {
    this.resultSet = resultSet;
    size = yaz4jlib.ZOOM_resultset_size(this.resultSet);
    this.conn = conn;
  }

  @Override
  public void finalize() {
    this._dispose();
  }

  /**
   * Read option by name.
   * @param name option name
   * @return option value
   */
  public String option(String name) {
    return yaz4jlib.ZOOM_resultset_option_get(resultSet, name);
  }

  /**
   * Write option with a given name.
   * @param name option name
   * @param value option value
   * @return result set (self) for chainability
   */
  public ResultSet option(String name, String value) {
    yaz4jlib.ZOOM_resultset_option_set(resultSet, name, value);
    return this;
  }

  public Record getRecord(long index) throws ZoomException {
    SWIGTYPE_p_ZOOM_record_p record =
      yaz4jlib.ZOOM_resultset_record(resultSet, index);
    //may be out of range or unsupported syntax
    if (record == null) {
      return null;
    }
    int errorCode = yaz4jlib.ZOOM_record_error(record, null, null, null);
    if (errorCode != 0) {
      throw new ZoomException("Record excpetion, code " + errorCode);
    }
    return new Record(record, this);
  }
  
  public List<Record> getRecords(long start, int count) throws ZoomException {
  	List<Record> out = new ArrayList<Record>(count);
  	
  	SWIGTYPE_p_p_ZOOM_record_p recs = yaz4jlib.new_zoomRecordArray(count);
  	yaz4jlib.ZOOM_resultset_records(resultSet, recs, start, count);
  	
  	for (int i = 0; i < count; i++) {
  		SWIGTYPE_p_ZOOM_record_p record = yaz4jlib.zoomRecordArray_getitem(recs, i);
  		if (record == null) {
  			continue;
  		}
  		
	  	int errorCode = yaz4jlib.ZOOM_record_error(record, null, null, null);
	    if (errorCode != 0) {
	      throw new ZoomException("Record excpetion, code " + errorCode);
	    }
	    
	    out.add(new Record(record, this));
  	}

    return out;
  }

  @Override
  public Iterator<Record> iterator() {
    return new Iterator<Record>() {
      private long cur;
      @Override
      public boolean hasNext() {
        return cur < size;
      }

      @Override
      public Record next() {
        try {
          return getRecord(cur++);
        } catch (ZoomException ze) {
          throw new NoSuchElementException(ze.getMessage());
        }
      }

      @Override
      public void remove() {
        throw new UnsupportedOperationException("remove operation not supported");
      }
    };
  }

  public ResultSet sort(String type, String spec) throws ZoomException {
    int ret = yaz4jlib.ZOOM_resultset_sort1(resultSet, type, spec);
    if (ret != 0) throw new ZoomException("Sorting resultset failed");
    return this;
  }

  public long getHitCount() {
    return size;
  }

  void _dispose() {
    if (!disposed) {
      yaz4jlib.ZOOM_resultset_destroy(resultSet);
      resultSet = null;
      conn = null;
      disposed = true;
    }
  }
}

@@ -253,29 +253,30 @@
 GTYPE_p_
-p_
 ZOOM_re
-cord
+sultset
 _p;%0Aimpo
@@ -299,38 +299,37 @@
 .SWIGTYPE_p_
+p_
 ZOOM_re
-sultset
+cord
 _p;%0Aimport o
@@ -2793,17 +2793,18 @@
 ion %7B%0A  
-%09
+  
 List%3CRec
@@ -2846,21 +2846,18 @@
 unt);%0A  
-%09%0A
   
-%09
 SWIGTYPE
@@ -2921,17 +2921,18 @@
 unt);%0A  
-%09
+  
 yaz4jlib
@@ -2993,13 +2993,10 @@
 ;%0A  
-%09%0A
   
-%09
 for 
@@ -3027,18 +3027,20 @@
 ++) %7B%0A  
-%09%09
+    
 SWIGTYPE
@@ -3064,16 +3064,24 @@
 record =
+%0A       
  yaz4jli
@@ -3118,18 +3118,20 @@
 , i);%0A  
-%09%09
+    
 if (reco
@@ -3150,11 +3150,14 @@
 %7B%0A  
-%09%09%09
+      
 cont
@@ -3168,21 +3168,20 @@
 ;%0A  
-%09%09%7D%0A  %09%09%0A%09
+    %7D%0A    
   
-%09
 int 
@@ -3246,17 +3246,18 @@
  null);%0A
-%09
+  
     if (
@@ -3274,17 +3274,18 @@
 != 0) %7B%0A
-%09
+  
       th
@@ -3350,22 +3350,18 @@
 e);%0A
-%09
     
-%7D%0A%09    %0A%09
+  %7D%0A  
     
@@ -3401,11 +3401,11 @@
 ;%0A  
-%09%7D%0A
+  %7D
 %0A   

Reformat only