//
//   Copyright 2019  SenX S.A.S.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

package io.warp10.script.functions;

import com.google.common.primitives.Longs;
import io.warp10.script.NamedWarpScriptFunction;
import io.warp10.script.WarpScriptException;
import io.warp10.script.WarpScriptStack;
import io.warp10.script.WarpScriptStackFunction;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;

/**
 * Converts a LONG to a byte array
 */
public class TOLONGBYTES extends NamedWarpScriptFunction implements WarpScriptStackFunction {
  
  public TOLONGBYTES(String name) {
    super(name);
  }
  
  @Override
  public Object apply(WarpScriptStack stack) throws WarpScriptException {
    
    Object o = stack.pop();
    
    if (o instanceof Long) {
      int nbBytes = ((Long) o).intValue();
      o = stack.pop();
      if (o instanceof Long && nbBytes > 0 && nbBytes <= 8) {
        //truncate the result to nbBytes when needed
        if (8 != nbBytes) {
          stack.push(Arrays.copyOfRange(Longs.toByteArray(((Long) o).longValue()), 8 - (int) nbBytes, 8));
        } else {
          stack.push(Longs.toByteArray(((Long) o).longValue()));
        }
      } else if (o instanceof List && nbBytes > 0 && nbBytes <= 8) {
        try {
          ByteBuffer bytes = ByteBuffer.allocate(nbBytes * ((List) o).size());
          if (8 == nbBytes) {
            for (Object el : (List) o) {
              bytes.putLong((Long) el);
            }
          } else if (4 == nbBytes) {
            for (Object el : (List) o) {
              bytes.putInt(((Long) el).intValue());
            }
          } else if (2 == nbBytes) {
            for (Object el : (List) o) {
              bytes.putShort(((Long) el).shortValue());
            }
          } else if (1 == nbBytes) {
            for (Object el : (List) o) {
              bytes.put(((Long) el).byteValue());
            }
          } else {
            // weird length are not optimized
            long v;
            for (Object el : (List) o) {
              v = ((Long) el).longValue() << (8 - nbBytes) * 8;
              for (int i = nbBytes - 1; i >= 0; i--) {
                bytes.put((byte) ((v & 0xff00000000000000L) >> 56));
                v <<= 8;
              }
            }
          }
          stack.push(bytes.array());
        } catch (Exception e) {
          throw new WarpScriptException(getName() + " operates on a LONG or a list of LONG and expects a number of output bytes between 1 and 8 on top of the stack.");
        }
      } else {
        throw new WarpScriptException(getName() + " operates on a LONG or a list of LONG and expects a number of output bytes between 1 and 8 on top of the stack.");
      }
    } else {
      throw new WarpScriptException(getName() + " operates on a LONG or a list of LONG and expects a number of output bytes between 1 and 8 on top of the stack.");
    }
    
    return stack;
  }
}

@@ -900,16 +900,43 @@
 Buffer;%0A
+import java.nio.ByteOrder;%0A
 import j
@@ -1834,74 +1834,149 @@
     
-ByteBuffer bytes = ByteBuffer.allocate(nbBytes * ((List) o).size()
+byte%5B%5D b = new byte%5BnbBytes * ((List) o).size()%5D;%0A          ByteBuffer bytes = ByteBuffer.wrap(b);%0A          bytes.order(ByteOrder.BIG_ENDIAN
 );%0A 
@@ -2022,33 +2022,32 @@
   for (Object el
- 
 : (List) o) %7B%0A  
@@ -2153,33 +2153,32 @@
   for (Object el
- 
 : (List) o) %7B%0A  
@@ -2296,33 +2296,32 @@
   for (Object el
- 
 : (List) o) %7B%0A  
@@ -2443,33 +2443,32 @@
   for (Object el
- 
 : (List) o) %7B%0A  
@@ -2640,17 +2640,16 @@
 bject el
- 
 : (List)
@@ -2749,32 +2749,27 @@
 i = 
-nbBytes - 1; i %3E= 0; i--
+0; i %3C nbBytes; i++
 ) %7B%0A
@@ -2805,34 +2805,10 @@
 te) 
-(
 (v
- & 0xff00000000000000L)
  %3E%3E 
@@ -2906,20 +2906,8 @@
 sh(b
-ytes.array()
 );%0A 
@@ -3057,32 +3057,41 @@
 of output bytes 
+per LONG 
 between 1 and 8 
@@ -3257,32 +3257,41 @@
 of output bytes 
+per LONG 
 between 1 and 8 
@@ -3459,16 +3459,25 @@
 t bytes 
+per LONG 
 between 

fix bytebuffer endianness