'use strict';

var nameToControllerMap = {},
  controllers = {},
  hintLog = angular.hint = require('angular-hint-log'),
  MODULE_NAME = 'Controllers',
  SEVERITY_ERROR = 1,
  SEVERITY_WARNING = 2;

/**
* Decorates $controller with a patching function to
* log a message if the controller is instantiated on the window
*/
angular.module('ngHintControllers', []).
  config(function ($provide) {
    $provide.decorator('$controller', function($delegate) {
        return function(ctrl, locals) {
          //If the controller name is passed, find the controller than matches it
          if(typeof ctrl === 'string') {
            if(nameToControllerMap[ctrl]) {
              ctrl = nameToControllerMap[ctrl];
            } else {
              //If the controller function cannot be found, check for it on the window
              checkUppercaseName(ctrl);
              checkControllerInName(ctrl);
              ctrl = window[ctrl] || ctrl;
              if(typeof ctrl === 'string') {
                throw new Error('The controller function for ' + ctrl + ' could not be found.' +
                  ' Is the function registered under that name?');
              }
            }
          }
          locals = locals || {};
          //If the controller is not in the list of already registered controllers
          //and it is not connected to the local scope, it must be instantiated on the window
          if(!controllers[ctrl] && (!locals.$scope || !locals.$scope[ctrl]) &&
              ctrl.toString().indexOf('@name ngModel.NgModelController#$render') === -1 &&
              ctrl.toString().indexOf('@name form.FormController') === -1) {
            if(angular.version.minor <= 2) {
              hintLog.logMessage(MODULE_NAME, 'It is against Angular best practices to ' +
                'instantiate a controller on the window. This behavior is deprecated in Angular' +
                ' 1.3.0', SEVERITY_WARNING);
            } else {
              hintLog.logMessage(MODULE_NAME, 'Global instantiation of controllers was deprecated' +
                ' in Angular 1.3.0. Define the controller on a module.', SEVERITY_ERROR);
            }
          }
          var ctrlInstance = $delegate.apply(this, [ctrl, locals]);
          return ctrlInstance;
        };
    });
});

/**
* Save details of the controllers as they are instantiated
* for use in decoration.
* Hint about the best practices for naming controllers.
*/
var originalModule = angular.module;

function checkUppercaseName(controllerName) {
  var firstLetter = controllerName.charAt(0);
  if(firstLetter !== firstLetter.toUpperCase() && firstLetter === firstLetter.toLowerCase()) {
    hintLog.logMessage(MODULE_NAME, 'The best practice is to name controllers with an' +
      ' uppercase first letter. Check the name of \'' + controllerName + '\'.', SEVERITY_WARNING);
  }
}

function checkControllerInName(controllerName) {
  var splitName = controllerName.split('Controller');
  if(splitName.length === 1 || splitName[splitName.length - 1] !== '') {
    hintLog.logMessage(MODULE_NAME, 'The best practice is to name controllers ending with ' +
      '\'Controller\'. Check the name of \'' + controllerName + '\'.', SEVERITY_WARNING);
  }
}

angular.module = function() {
  var module = originalModule.apply(this, arguments),
    originalController = module.controller;
  module.controller = function(controllerName, controllerConstructor) {
    nameToControllerMap[controllerName] = controllerConstructor;
    controllers[controllerConstructor] = controllerConstructor;
    checkUppercaseName(controllerName);
    checkControllerInName(controllerName);
    return originalController.apply(this, arguments);
  };
  return module;
};

@@ -425,24 +425,73 @@
 oller', 
-function
+controllerDecorator);%0A  %7D);%0A%0Afunction controllerDecorator
 ($delega
@@ -496,22 +496,16 @@
 gate) %7B%0A
-      
   return
@@ -526,30 +526,24 @@
 , locals) %7B%0A
-      
     //If the
@@ -606,22 +606,16 @@
 ches it%0A
-      
     if(t
@@ -647,22 +647,16 @@
 %7B%0A      
-    
-  
 if(nameT
@@ -683,30 +683,24 @@
 ) %7B%0A        
-  
-    
 ctrl = nameT
@@ -719,38 +719,32 @@
 ap%5Bctrl%5D;%0A      
-    
-  
 %7D else %7B%0A       
@@ -728,38 +728,32 @@
 %0A      %7D else %7B%0A
-      
         //If the
@@ -821,30 +821,24 @@
 dow%0A        
-      
 checkUpperca
@@ -859,22 +859,16 @@
         
-  
-    
 checkCon
@@ -892,30 +892,24 @@
 l);%0A        
-     
- 
 ctrl = windo
@@ -925,22 +925,16 @@
 %7C ctrl;%0A
-      
         
@@ -974,22 +974,16 @@
         
- 
-     
 throw ne
@@ -1067,22 +1067,16 @@
         
-      
 ' Is the
@@ -1120,38 +1120,32 @@
 ');%0A        
-     
- 
 %7D%0A      
       %7D%0A    
@@ -1136,34 +1136,16 @@
     
-    
-  %7D%0A      
+%7D%0A
     %7D%0A
-      
     
@@ -1167,22 +1167,16 @@
  %7C%7C %7B%7D;%0A
-      
     //If
@@ -1244,22 +1244,16 @@
 rollers%0A
-      
     //an
@@ -1332,22 +1332,16 @@
  window%0A
-      
     if(!
@@ -1405,38 +1405,32 @@
 rl%5D) &&%0A        
-     
- 
 ctrl.toString().
@@ -1498,22 +1498,16 @@
         
-      
 ctrl.toS
@@ -1567,22 +1567,16 @@
 %7B%0A      
- 
-     
 if(angul
@@ -1596,30 +1596,24 @@
 nor %3C= 2) %7B%0A
-      
         hint
@@ -1695,22 +1695,16 @@
         
-     
- 
 'instant
@@ -1788,22 +1788,16 @@
         
-      
 ' 1.3.0'
@@ -1817,22 +1817,16 @@
 RNING);%0A
-      
       %7D 
@@ -1840,22 +1840,16 @@
         
-    
-  
 hintLog.
@@ -1923,30 +1923,24 @@
 precated' +%0A
-      
           ' 
@@ -2021,34 +2021,16 @@
     
-      %7D%0A          %7D%0A      
+%7D%0A    %7D%0A
     
@@ -2087,22 +2087,16 @@
 cals%5D);%0A
-      
     retu
@@ -2118,28 +2118,12 @@
 ;%0A  
-      %7D;%0A    %7D);%0A%7D);
+%7D;%0A%7D
 %0A%0A/*

move to hoisted fn