import { decodeKeypath, getKey } from 'shared/keypaths';
import FAILED_LOOKUP from './get/FAILED_LOOKUP';


var empty = {};

export default function Viewmodel$get ( keypath, options ) {
	var ractive = this.ractive,
		cache = this.cache,
		mapping,
		value,
		computation,
		wrapped,
		captureGroup;

	options = options || empty;

	// capture the keypath, if we're inside a computation
	if ( options.capture && ( captureGroup = this.captureGroups[ this.captureGroups.length - 1 ] ) ) {
		if ( !~captureGroup.indexOf( keypath ) ) {
			captureGroup.push( keypath );
		}
	}

	if ( mapping = this.mappings[ getKey( keypath ) ] ) {
		return mapping.get( keypath, options );
	}

	if ( keypath[0] === '@' ) {
		return decodeKeypath( keypath );
	}

	if ( cache[ keypath ] === undefined ) {

		// Is this a computed property?
		if ( ( computation = this.computations[ keypath ] ) && !computation.bypass ) {
			value = computation.get();
			this.adapt( keypath, value );
		}

		// Is this a wrapped property?
		else if ( wrapped = this.wrapped[ keypath ] ) {
			value = wrapped.value;
		}

		// Is it the root?
		else if ( !keypath ) {
			this.adapt( '', ractive.data );
			value = ractive.data;
		}

		// No? Then we need to retrieve the value one key at a time
		else {
			value = retrieve( this, keypath );
		}

		cache[ keypath ] = value;
	} else {
		value = cache[ keypath ];
	}

	if ( !options.noUnwrap && ( wrapped = this.wrapped[ keypath ] ) ) {
		value = wrapped.get();
	}

	return value === FAILED_LOOKUP ? void 0 : value;
}

function retrieve ( viewmodel, keypath ) {

	var keys, key, parentKeypath, parentValue, cacheMap, value, wrapped;

	keys = keypath.split( '.' );
	key = keys.pop();
	parentKeypath = keys.join( '.' );

	parentValue = viewmodel.get( parentKeypath );

	if ( wrapped = viewmodel.wrapped[ parentKeypath ] ) {
		parentValue = wrapped.get();
	}

	if ( parentValue === null || parentValue === undefined ) {
		return;
	}

	// update cache map
	if ( !( cacheMap = viewmodel.cacheMap[ parentKeypath ] ) ) {
		viewmodel.cacheMap[ parentKeypath ] = [ keypath ];
	} else {
		if ( cacheMap.indexOf( keypath ) === -1 ) {
			cacheMap.push( keypath );
		}
	}

	// If this property doesn't exist, we return a sentinel value
	// so that we know to query parent scope (if such there be)
	if ( typeof parentValue === 'object' && !( key in parentValue ) ) {
		return viewmodel.cache[ keypath ] = FAILED_LOOKUP;
	}

	value = parentValue[ key ];

	// Do we have an adaptor for this value?
	viewmodel.adapt( keypath, value, false );

	// Update cache
	viewmodel.cache[ keypath ] = value;
	return value;
}

@@ -23,16 +23,28 @@
 , getKey
+, getKeypath
  %7D from 
@@ -335,16 +335,167 @@
 empty;%0A%0A
+%09// TODO this is temporary. Eventually we should only use Keypath objects%0A%09if ( typeof keypath === 'string' ) %7B%0A%09%09keypath = getKeypath( keypath );%0A%09%7D%0A%0A
 %09// capt
@@ -679,16 +679,20 @@
  keypath
+.str
  ) ) %7B%0A%09
@@ -711,32 +711,36 @@
 up.push( keypath
+.str
  );%0A%09%09%7D%0A%09%7D%0A%0A%09if 
@@ -770,25 +770,24 @@
 gs%5B 
-getKey( keypath )
+keypath.firstKey
  %5D )
@@ -810,32 +810,36 @@
 ing.get( keypath
+.str
 , options );%0A%09%7D%0A
@@ -856,19 +856,18 @@
 path
-%5B0%5D === '@'
+.isSpecial
  ) %7B
@@ -880,32 +880,21 @@
 urn 
-decodeKeypath( keypath )
+keypath.value
 ;%0A%09%7D
@@ -1100,24 +1100,28 @@
 apt( keypath
+.str
 , value );%0A%09
@@ -1275,16 +1275,22 @@
 f ( 
-!
 keypath
+.isRoot
  ) %7B
@@ -1742,34 +1742,8 @@
 %09var
- keys, key, parentKeypath,
  par
@@ -1783,93 +1783,8 @@
 d;%0A%0A
-%09keys = keypath.split( '.' );%0A%09key = keys.pop();%0A%09parentKeypath = keys.join( '.' );%0A%0A
 %09par
@@ -1809,29 +1809,30 @@
 el.get( 
-parentKeypath
+keypath.parent
  );%0A%0A%09if
@@ -1863,29 +1863,30 @@
 rapped%5B 
-parentKeypath
+keypath.parent
  %5D ) %7B%0A%09
@@ -2054,29 +2054,34 @@
 cheMap%5B 
-parentKeypath
+keypath.parent.str
  %5D ) ) %7B
@@ -2107,21 +2107,26 @@
 ap%5B 
-parentKeypath
+keypath.parent.str
  %5D =
@@ -2131,24 +2131,28 @@
  = %5B keypath
+.str
  %5D;%0A%09%7D else 
@@ -2185,16 +2185,20 @@
  keypath
+.str
  ) === -
@@ -2220,32 +2220,36 @@
 ap.push( keypath
+.str
  );%0A%09%09%7D%0A%09%7D%0A%0A%09// 
@@ -2415,16 +2415,28 @@
 & !( key
+path.lastKey
  in pare
@@ -2531,16 +2531,28 @@
 lue%5B key
+path.lastKey
  %5D;%0A%0A%09//
@@ -2615,16 +2615,20 @@
  keypath
+.str
 , value,

use Keypath object inside viewmodel.get()