/*
 *  Copyright (C) 2011 The Animo Project
 *  http://animotron.org
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 3
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.animotron.graph.builder;

import org.animotron.AbstractExpression;
import org.animotron.Expression;
import org.animotron.Properties;
import org.animotron.exception.AnimoException;
import org.animotron.graph.GraphOperation;
import org.animotron.statement.operator.THE;
import org.animotron.statement.relation.IS;
import org.animotron.utils.MessageDigester;
import org.neo4j.graphdb.Relationship;

import java.io.*;
import java.security.MessageDigest;
import java.util.UUID;
import java.util.regex.Pattern;

import static org.animotron.Expression._;
import static org.animotron.graph.AnimoGraph.getStorage;


/**
 * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
 * @author <a href="mailto:gazdovsky@gmail.com">Evgeny Gazdovsky</a>
 * 
 */
public class BinaryBuilder extends AbstractExpression {
	
	private final static File BIN_STORAGE = new File(getStorage(), "binany");
	private final static File TMP_STORAGE = new File(getStorage(), "tmp");
	
	static {
		BIN_STORAGE.mkdirs();
		TMP_STORAGE.mkdirs();
	}

    private static File getFolder(String hash) {
        return new File(new File(BIN_STORAGE, hash.substring(0, 2)), hash.substring(0, 4));
    }

    private static File getFile(File folder, String hash){
        return new File(folder,  hash);
    }

    public static File getFile(String hash){
        return new File(getFolder(hash),  hash);
    }

    public BinaryBuilder (InputStream stream, String path) throws IOException, AnimoException {

        String txID = UUID.randomUUID().toString();

        File tmp = new File(TMP_STORAGE, txID);
        tmp.createNewFile();
        OutputStream out = new FileOutputStream(tmp);

        byte buf[] = new byte[1024 * 4];
        int len;
        MessageDigest md = MessageDigester.md();

        while((len=stream.read(buf))>0) {
            out.write(buf,0,len);
            md.update(buf,0,len);
        }

        out.close();
        stream.close();

        String hash = MessageDigester.byteArrayToHex(md.digest());
        File dir = getFolder(hash);
        File bin = getFile(dir, hash);

        if (bin.exists()) {

            tmp.delete();
            System.out.println("File \"" + bin.getPath() + "\" already stored");

        } else {

            dir.mkdirs();

            if (!tmp.renameTo(bin)) {
                tmp.delete();
                throw new IOException("transaction can not be finished");

            } else {

                startGraph();

                    start(IS._, "file");
                    end();

                    String[] parts = path.split(Pattern.quote(File.separator));
                    
                    Expression prev = null;
                    for (String part : parts) {
                        if (!part.isEmpty()) {
                            if (prev == null) {
                                prev = new Expression(
                                        _(IS._, part)
                                );
                            } else {
                                prev = new Expression(
                                    _(IS._, THE._.name(prev)),
                                    _(IS._, part)
                                );
                            }
                        }
                    }

                    if (prev != null) {
                        start(IS._, THE._.name(prev));
                        end();
                    }

                endGraph(new SetBinHash(this, hash));

                if (!successful()) {
                    tmp.delete();
                }

            }

            System.out.println("Store the file \"" + bin.getPath() + "\"");

        }

    }

    private class SetBinHash implements GraphOperation<Void> {
        private Relationship r;
        private String hash;
        public SetBinHash(Relationship r, String hash){
            this.hash = hash;
            this.r = r;
        }
        @Override
        public Void execute() {
            Properties.BIN.set(r.getEndNode(), hash);
            return null;
        }
    }
	
}

@@ -1037,53 +1037,8 @@
 on;%0A
-import org.animotron.statement.operator.THE;%0A
 impo
@@ -1275,50 +1275,8 @@
 n;%0A%0A
-import static org.animotron.Expression._;%0A
 impo
@@ -3487,24 +3487,302 @@
 sEmpty()) %7B%0A
+                            start(IS._, part);%0A                            end();%0A                        %7D%0A                    %7D%0A%0A//                    Expression prev = null;%0A//                    for (String part : parts) %7B%0A//                        if (!part.isEmpty()) %7B%0A//
             
@@ -3809,32 +3809,34 @@
 prev == null) %7B%0A
+//
                 
@@ -3866,32 +3866,34 @@
 new Expression(%0A
+//
                 
@@ -3922,32 +3922,34 @@
   _(IS._, part)%0A
+//
                 
@@ -3959,32 +3959,34 @@
              );%0A
+//
                 
@@ -4006,16 +4006,18 @@
  else %7B%0A
+//
         
@@ -4063,16 +4063,18 @@
 ession(%0A
+//
         
@@ -4128,16 +4128,18 @@
 prev)),%0A
+//
         
@@ -4180,16 +4180,18 @@
 , part)%0A
+//
         
@@ -4217,16 +4217,18 @@
      );%0A
+//
         
@@ -4241,32 +4241,34 @@
               %7D%0A
+//
                 
@@ -4269,32 +4269,34 @@
               %7D%0A
+//
                 
@@ -4293,33 +4293,37 @@
               %7D%0A
-%0A
+//%0A//
                 
@@ -4342,24 +4342,26 @@
  != null) %7B%0A
+//
             
@@ -4399,24 +4399,26 @@
 ame(prev));%0A
+//
             
@@ -4428,32 +4428,34 @@
          end();%0A
+//
                 

remove a dummy nodes for binary files