package org.archive.format.warc;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.UUID;

import org.archive.format.http.HttpConstants;
import org.archive.format.http.HttpHeaders;
import org.archive.util.DateUtils;
import org.archive.util.StreamCopy;

public class WARCRecordWriter implements WARCConstants, HttpConstants 
{
  private static final String SCHEME = "urn:uuid";
  private static final String SCHEME_COLON = SCHEME + ":";
	
  /** 
   * Alternate version of writeRecord() which takes a byte[] rather
   * than an InputStream.  This is handy so we don't have to copy the
   * input into another buffer just to count the number of bytes, which
   * we do in the other one.      
   */
  private void writeRecord( OutputStream out, 
                            HttpHeaders headers, 
                            byte[] contents, 
                            int trailingCRLFs) throws IOException
  {
    if ( contents == null ) 
      {
        headers.add(CONTENT_LENGTH, "0");
      }
    else
      {
        headers.add(CONTENT_LENGTH,String.valueOf(contents.length));
      }
    
    out.write(WARC_ID.getBytes(DEFAULT_ENCODING));
    out.write(CR);
    out.write(LF);
    headers.write(out);
  
    if (contents != null) 
      {
        out.write( contents );
      }
    for (int i = 0; i < trailingCRLFs; i++)
      {
        out.write(CR);
        out.write(LF);
      }
  }

  public void writeWARCInfoRecord(OutputStream out, 
                                  String filename, 
                                  byte[] contents ) throws IOException
  {
    // WARC/1.0
    // WARC-Type: warcinfo
    // WARC-Date: 2010-10-08T07:00:26Z
    // WARC-Filename: LOC-MONTHLY-014-20101008070022-00127-crawling111.us.archive.org.warc.gz
    // WARC-Record-ID: <urn:uuid:05de9500-7047-4206-aa7f-346a0dc91b1f>
    // Content-Type: application/warc-fields
    // Content-Length: 600

    HttpHeaders headers = new HttpHeaders();
    headers.add(HEADER_KEY_TYPE, WARCINFO);
    headers.add(HEADER_KEY_DATE, DateUtils.getLog14Date());
    headers.add(HEADER_KEY_FILENAME, filename);
    headers.add(HEADER_KEY_ID, makeRecordId());
    headers.add(CONTENT_TYPE,WARC_FIELDS_TYPE);
    writeRecord(out,headers,contents,2);			
  }

  public void writeJSONMetadataRecord( OutputStream out,
                                       byte[] contents,
                                       String targetURI,
                                       Date originalDate,
                                       String origRecordId ) throws IOException
  {
    HttpHeaders headers = new HttpHeaders();
    headers.add(HEADER_KEY_TYPE, METADATA);
    headers.add(HEADER_KEY_URI, targetURI);
    headers.add(HEADER_KEY_DATE, DateUtils.getLog14Date(originalDate));
    headers.add(HEADER_KEY_ID, makeRecordId());
    headers.add(HEADER_KEY_REFERS_TO, origRecordId);
    
    headers.add(CONTENT_TYPE,"application/json");
    writeRecord(out, headers, contents, 1);
  }

  private String makeRecordId() 
  {
    StringBuilder recID = new StringBuilder();
    recID.append("<").append(SCHEME_COLON);
    recID.append(UUID.randomUUID().toString());
    recID.append(">");
    return recID.toString();
  }

}

@@ -522,247 +522,330 @@
   * 
-Alternate version of writeRecord() which takes a byte%5B%5D rather%0A   * than an InputS
+Write the headers and contents as a WARC record to the given%0A   * output s
 tream.
+%0A
   
-This is handy so we don't have to copy the%0A   * input into another buffer just to count the number of bytes, which%0A   * we do in the other one.      
+ *%0A   * WARC record format:%0A   * %3Cpre%3Ewarc-file = 1*warc-record%0A   * warc-record = header CRLF block CRLF CRLF%0A   * header = version warc-fields%0A   * version = %22WARC/0.18%22 CRLF%0A   * warc-fields = *named-field CRLF%0A   * block = *OCTET%3C/pre%3E
 %0A   
@@ -991,56 +991,8 @@
 ents
-, %0A                            int trailingCRLFs
 ) th
@@ -1282,24 +1282,145 @@
 t.write(LF);
+%0A%0A    // NOTE: HttpHeaders.write() method includes the trailing CRLF.%0A    //       So we don't need to write it out here.
 %0A    headers
@@ -1443,16 +1443,17 @@
     if (
+ 
 contents
@@ -1460,16 +1460,17 @@
  != null
+ 
 ) %0A     
@@ -1515,31 +1515,26 @@
   %7D%0A
+%0A
     
-for (int i = 0; i %3C
+// Emit the 2
  tra
@@ -1542,32 +1542,63 @@
 ling
+ 
 CRLF
-s; i++)%0A      %7B%0A    
+ sequences.%0A    out.write(CR);%0A    out.write(LF);%0A
     
@@ -1612,28 +1612,24 @@
 te(CR);%0A    
-    
 out.write(LF
@@ -1631,24 +1631,16 @@
 te(LF);%0A
-      %7D%0A
   %7D%0A%0A  p
@@ -2469,15 +2469,10 @@
 ents
-,2);%09%09%09
+);
 %0A  %7D
@@ -3188,11 +3188,8 @@
 ents
-, 1
 );%0A 

Fix https://github.com/internetarchive/archive-commons/issues/2