'use strict';

import React, {
  Image,
  Platform,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

import autobind from 'autobind-decorator';
import invariant from 'invariant';
import cloneReferencedElement from 'react-native-clone-referenced-element';

import ExNavigatorStyles from './ExNavigatorStyles';
import ExSceneConfigs from './ExSceneConfigs';
import Layout from './Layout';

import { BackIcon } from './ExNavigatorIcons';

import type { Navigator } from 'react-native';
import type * as ExNavigator from './ExNavigator';
import type * as ExRoute from './ExRoute';

type BarStyles = {
  titleStyle?: any;
  barButtonTextStyle?: any;
  barButtonIconStyle?: any;
};

class NavigationBarRouteMapper {
  constructor(navigator: ExNavigator, styles: BarStyles) {
    this._navigator = navigator;
    this._titleStyle = styles.titleStyle;
    this._barButtonTextStyle = styles.barButtonTextStyle;
    this._barButtonIconStyle = styles.barButtonIconStyle;
  }

  Title(
    route: ExRoute,
    navigator: Navigator,
    index: number,
    state: Object
  ): ?React.Component {
    if (route.renderTitle) {
      return route.renderTitle(this._navigator, index, state);
    }

    if (!route.getTitle) {
      return null;
    }

    return (
      <Text style={[ExNavigatorStyles.barTitleText, this._titleStyle]}>
        {shortenTitle(route.getTitle(this._navigator, index, state))}
      </Text>
    );
  }

  LeftButton(
    route: ExRoute,
    navigator: Navigator,
    index: number,
    state: Object
  ): ?React.Component {

    if (route.renderLeftButton) {
      return route.renderLeftButton(this._navigator, index, state);
    }

    if (index === 0) {
      return null;
    }

    let previousIndex = index - 1;
    let previousRoute = state.routeStack[previousIndex];
    return this._renderBackButton(previousRoute, this._navigator, previousIndex, state);
  }

  _renderBackButton(
    previousRoute: ExRoute,
    navigator: Navigator,
    previousIndex: number,
    state: Object
  ): ?React.Component {
    if (previousRoute.renderBackButton) {
      return previousRoute.renderBackButton(this._navigator, previousIndex, state);
    }

    let title;
    if (previousRoute.getTitle) {
      title = previousRoute.getTitle(this._navigator, previousIndex, state);
    }

    if (title) {
      var buttonText =
        <Text style={[
          ExNavigatorStyles.barButtonText,
          ExNavigatorStyles.barBackButtonText,
          this._barButtonTextStyle,
        ]}>
          {title}
        </Text>;
    }

    return (
      <TouchableOpacity
        pressRetentionOffset={ExNavigatorStyles.barButtonPressRetentionOffset}
        onPress={() => this._navigator.pop()}
        style={[ExNavigatorStyles.barBackButton, styles.backButtonStyle]}>
        <BackIcon
          style={[
            ExNavigatorStyles.barButtonIcon,
            this._barButtonIconStyle,
          ]}
        />
        {buttonText}
      </TouchableOpacity>
    );
  }

  RightButton(
    route: ExRoute,
    navigator: Navigator,
    index: number,
    state: Object
  ): ?React.Component {
    if (route.renderRightButton) {
      return route.renderRightButton(this._navigator, index, state);
    }
  }
};

export default class ExRouteRenderer {
  constructor(navigator: ExNavigator, styles: BarStyles) {
    this._previousRoute = null;
    this.navigationBarRouteMapper = new NavigationBarRouteMapper(
      navigator,
      styles,
    );
  }

  @autobind
  configureScene(route: ExRoute): Object {
    if (route.configureScene) {
      let sceneConfig = route.configureScene();
      if (sceneConfig) {
        return sceneConfig;
      }
    }

    if (Platform.OS === 'android') {
      return ExSceneConfigs.Fade;
    } else {
      return ExSceneConfigs.PushFromRight;
    }
  }

  @autobind
  renderScene(route: ExRoute, navigator: ExNavigator): React.Component {
    if (route.renderScene) {
      let scene = route.renderScene(navigator);
      if (!scene) {
        return scene;
      }
      return cloneReferencedElement(scene, {
        ref: component => { route.scene = component; },
      });
    }

    invariant(
      route.getSceneClass,
      'The route must implement renderScene or getSceneClass',
    );
    let Component = route.getSceneClass();
    return (
      <Component
        ref={component => { route.scene = component; }}
        navigator={navigator}
      />
    );
  }

  @autobind
  onWillFocus(event) {
    let { data: { route } } = event;
    if (route.onWillFocus) {
      route.onWillFocus(event);
    }
    // The component isn't mounted yet if this is the first time it's rendered
    if (route.scene && route.scene.componentWillFocus) {
      route.scene.componentWillFocus(event);
    }

    if (this._previousRoute) {
      if (this._previousRoute.onWillBlur) {
        this._previousRoute.onWillBlur(event);
      }
      let previousScene = this._previousRoute.scene;
      if (previousScene && previousScene.componentWillBlur) {
        previousScene.componentWillBlur(event);
      }
    }
  }

  @autobind
  onDidFocus(event) {
    let { data: { route } } = event;
    if (route.onDidFocus) {
      route.onDidFocus(event);
    }
    if (route.scene.componentDidFocus) {
      route.scene.componentDidFocus(event);
    }

    if (this._previousRoute) {
      if (this._previousRoute.onDidBlur) {
        this._previousRoute.onDidBlur(event);
      }
      let previousScene = this._previousRoute.scene;
      if (previousScene && previousScene.componentDidBlur) {
        previousScene.componentDidBlur(event);
      }
    }
    this._previousRoute = route;
  }
};

// Long titles will run into the left and right button text or overflow even
// further and just generally look gross so we try to limit the damage by
// shortening the title text.
//
// iOS does this by moving the title to take up the available space (to the
// left or right if the buttons leave space), and then ellipsising as necessary
// by measuring the actual text, etc. We can eventually but for now, we'll just
// limit titles to at most 18 characters.
function shortenTitle(title) {
  if (title.length > 18) {
    return title.substr(0, 18) + '…';
  } else {
    return title;
  }
}

let styles = StyleSheet.create({
  backButton: {
    flexDirection: 'row',
    alignItems: 'center',
  },
});

export default ExRouteRenderer;

@@ -4760,34 +4760,73 @@
 %0A    %7D%0A%0A    
-if (this._
+let previousRoute = this._previousRoute;%0A    if (
 previousRout
@@ -4832,38 +4832,32 @@
 te) %7B%0A      if (
-this._
 previousRoute.on
@@ -4868,38 +4868,32 @@
 Blur) %7B%0A        
-this._
 previousRoute.on
@@ -4935,38 +4935,32 @@
 previousScene = 
-this._
 previousRoute.sc
@@ -5240,32 +5240,47 @@
  if (route.scene
+ && route.scene
 .componentDidFoc
@@ -5336,34 +5336,73 @@
 %0A    %7D%0A%0A    
-if (this._
+let previousRoute = this._previousRoute;%0A    if (
 previousRout
@@ -5416,22 +5416,16 @@
     if (
-this._
 previous
@@ -5447,30 +5447,24 @@
 ) %7B%0A        
-this._
 previousRout
@@ -5513,30 +5513,24 @@
 iousScene = 
-this._
 previousRout

Add checks to see if route.scene exists for componentDidFocus