/* Copyright (c) 2010-2014 John Roche, MIT License */
'use strict';

var typeis = require('type-of-is');

var typeMap = {
	              'Integer': 'integerValue',
	              'Double': 'doubleValue',
	              'Boolean': 'booleanValue',
	              'String': 'stringValue',
	              'Object': 'blobKeyValue',
	              'Array': 'blobKeyValue',
	              'Date': 'dateTimeValue'
	            };

/**
 * Create the property value object for the Google Datastore
 *
 * params
 * value - The value to store in the Datastore
 */
exports.createValueObject = function(value){
  var svt = getStoreValueType(value),
      valueObject = {};

  // TODO: update Array to listValue
 if(svt === 'blobKeyValue'){
     value = JSON.stringify(value);
    }
    
    valueObject[svt] = value;
    
    return valueObject; 
};

/**
 * Convert a Javascript variable type to a corresponding Google Datastore type
 *
 * params
 * v - A variable
 */
function getStoreValueType(v){
    var type = typeis.string(v);
    if(type === 'Number'){
      type = isInteger(v) ? 'Integer' : 'Double';
      }
      return typeMap[type];
    }

/**
 * Check whether a Number is an Integer
 *
 * params
 * n - A Number
 */
function isInteger(n) {
    return n === +n && n === (n|0);
}


/**
 * Translate a database entity into a seneca entity
 *
 * params
 * senecaEntity - A seneca entity to translate into database entity.
 * dbEntity - A database entity
 */
exports.translate = function(senecaEntity, dbEntity){
  var fields = {};

  fields.id = dbEntity.entity.key.path[0].id;
  var properties = dbEntity.entity.properties;
  for(var p in properties){
    if(properties.hasOwnProperty(p)){
      fields[p] = createField(properties[p]);
    }
  }

  return senecaEntity.make$(fields);
};

/**
 * Convert a Google Datastore value object into a Javascript variable
 *
 * params
 * valueOb - A Google Datastore value object
 */
function createField(valueOb){
  var dbType = '',
  	  keys = Object.keys(valueOb);

  for(var i in keys){
    if(keys[i].indexOf('Value') !== -1){
      dbType = keys[i];
    }
  }

  switch(dbType) {
	case 'stringValue':
	    return valueOb.stringValue;
	case 'integerValue':
	    return parseInt(valueOb.integerValue);
	case 'doubleValue':
	    return parseFloat(valueOb.doubleValue);
	case 'booleanValue':
	    return 'true' === dbType;
	case 'dateTimeValue':
	    return new Date(Date.parse(valueOb.dateTimeValue));
	case 'blobKeyValue':
	    return JSON.parse(valueOb.blobKeyValue);    
	default:
	    return;
	  }
}
@@ -398,16 +398,101 @@
 meValue'
+,%0A                'undefined': 'blobKeyValue',%0A                'null': 'blobKeyValue'
 %0A%09      
@@ -675,16 +675,18 @@
 value)%7B%0A
+  
   var sv
@@ -717,24 +717,26 @@
 lue),%0A      
+  
 valueObject 
@@ -744,16 +744,18 @@
  %7B%7D;%0A%0A  
+ 
+ 
 // TODO:
@@ -781,16 +781,19 @@
 stValue%0A
+   
  if(svt 
@@ -814,24 +814,25 @@
 lue')%7B%0A     
+ 
 value = JSON
@@ -856,24 +856,82 @@
 ;%0A    %7D%0A    
+if(value === undefined)%7B%0A      value = 'undefined';%0A    %7D%0A
 %0A    valueOb
@@ -949,20 +949,16 @@
  value;%0A
-    
 %0A    ret
@@ -1663,24 +1663,42 @@
  fields = %7B%7D
+,%0A      properties
 ;%0A%0A  fields.
@@ -1736,20 +1736,16 @@
 %5D.id;%0A  
-var 
 properti
@@ -1937,24 +1937,278 @@
 ields);%0A%7D;%0A%0A
+%0A/**%0A * Get the entity id from the result object. This could be%0A * path.id or path.name%0A *%0A * params.%0A * dbEntity - A database entity%0A */%0Afunction getId(dbEntity)%7B%0A  return dbEntity.entity.key.path%5B0%5D.id %7C%7C%0A         dbEntity.entity.key.path%5B0%5D.name;%0A%7D%0A%0A%0A
 /**%0A * Conve
@@ -2875,24 +2875,120 @@
 alue':%0A%09    
+if(valueOb.blobKeyValue === 'undefined')%7B%0A        return undefined;%0A      %7D%0A      else%7B%0A        
 return JSON.
@@ -3015,16 +3015,37 @@
 yValue);
+%0A      %7D%0A      break;
     %0A%09de

Fix to support null and undefined types being stored