text: 'use strict';
  
  var request = require('request');
  
  exports.init = function(req, res){
    if (req.isAuthenticated()) {
      res.redirect(req.user.defaultReturnUrl());
    }
    else {
      res.render('jade/signup/index.jade', {
        oauthMessage: '',
        oauthTwitter: !!req.app.config.oauth.twitter.key,
        oauthGitHub: !!req.app.config.oauth.github.key,
        oauthFacebook: !!req.app.config.oauth.facebook.key,
        oauthGoogle: !!req.app.config.oauth.google.key,
        oauthTumblr: !!req.app.config.oauth.tumblr.key
      });
    }
  };
  
  exports.signup = function(req, res){
    var workflow = req.app.utility.workflow(req, res);
  
    workflow.on('validate', function() {
      if (!req.body.username) {
        workflow.outcome.errfor.username = 'required';
      }
      else if (!/^[a-zA-Z0-9\-\_]+$/.test(req.body.username)) {
        workflow.outcome.errfor.username = 'only use letters, numbers, \'-\', \'_\'';
      }
  
      if (!req.body.email) {
        workflow.outcome.errfor.email = 'required';
      }
      else if (!/^[a-zA-Z0-9\-\_\.\+]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z0-9\-\_]+$/.test(req.body.email)) {
        workflow.outcome.errfor.email = 'invalid email format';
      }
  
      if (!req.body.password) {
        workflow.outcome.errfor.password = 'required';
      }
  
      if(!req.body.recaptcha_response) {
        workflow.outcome.errfor.recaptcha = 'required';
      }
  
      if (workflow.hasErrors()) {
        return workflow.emit('response');
      } else {
        request.post('https://www.google.com/recaptcha/api/siteverify',
            {
              formData: {
                'secret': req.app.config.grecaptcha.secret,
                'response': req.body.recaptcha_response
              }, json: true
            },
            function (error, response, body) {
              if (!error && response.statusCode == 200 && body && body.success) {
                workflow.emit('duplicateUsernameCheck');
              } else {
                workflow.outcome.errfor.recaptcha = 'invalid captcha';
                return workflow.emit('response');
              }
            }
        );
      }
    });
  
    workflow.on('duplicateUsernameCheck', function() {
      req.app.db.models.User.findOne({ username: req.body.username }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        if (user) {
          workflow.outcome.errfor.username = 'username already taken';
          return workflow.emit('response');
        }
  
        workflow.emit('duplicateEmailCheck');
      });
    });
  
    workflow.on('duplicateEmailCheck', function() {
      req.app.db.models.User.findOne({ email: req.body.email.toLowerCase() }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        if (user) {
          workflow.outcome.errfor.email = 'email already registered';
          return workflow.emit('response');
        }
  
        workflow.emit('createUser');
      });
    });
  
    workflow.on('createUser', function() {
      req.app.db.models.User.encryptPassword(req.body.password, function(err, hash) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        var fieldsToSet = {
          isActive: 'yes',
          username: req.body.username,
          email: req.body.email.toLowerCase(),
          password: hash,
          search: [
            req.body.username,
            req.body.email
          ]
        };
        req.app.db.models.User.create(fieldsToSet, function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }
  
          workflow.user = user;
          workflow.emit('createAccount');
        });
      });
    });
  
    workflow.on('createAccount', function() {
      var fieldsToSet = {
        isVerified: req.app.config.requireAccountVerification ? 'no' : 'yes',
        'name.full': workflow.user.username,
        user: {
          id: workflow.user._id,
          name: workflow.user.username
        },
        search: [
          workflow.user.username
        ]
      };
  
      req.app.db.models.Account.create(fieldsToSet, function(err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        //update user with account
        workflow.user.roles.account = account._id;
        workflow.user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }
  
          workflow.emit('sendWelcomeEmail');
        });
      });
    });
  
    workflow.on('sendWelcomeEmail', function() {
      req.app.utility.sendmail(req, res, {
        from: req.app.config.smtp.from.name +' <'+ req.app.config.smtp.from.address +'>',
        to: req.body.email,
        subject: 'Your '+ req.app.config.projectName +' Account',
        textPath: 'jade/signup/email-text.jade',
        htmlPath: 'jade/signup/email-html.jade',
        locals: {
          username: req.body.username,
          email: req.body.email,
          loginURL: req.protocol +'://'+ req.headers.host +'/login/',
          projectName: req.app.config.projectName
        },
        success: function(message) {
          workflow.emit('logUserIn');
        },
        error: function(err) {
          console.log('Error Sending Welcome Email: '+ err);
          workflow.emit('logUserIn');
        }
      });
    });
  
    workflow.on('logUserIn', function() {
      req._passport.instance.authenticate('local', function(err, user, info) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        if (!user) {
          workflow.outcome.errors.push('Login failed. That is strange.');
          return workflow.emit('response');
        }
        else {
          req.login(user, function(err) {
            if (err) {
              return workflow.emit('exception', err);
            }
  
            workflow.outcome.defaultReturnUrl = user.defaultReturnUrl();
            workflow.emit('response');
          });
        }
      })(req, res);
    });
  
    workflow.emit('validate');
  };
  
  exports.signupTwitter = function(req, res, next) {
    req._passport.instance.authenticate('twitter', function(err, user, info) {
      if (!info || !info.profile) {
        return res.redirect('/signup/');
      }
  
      req.app.db.models.User.findOne({ 'twitter.id': info.profile.id }, function(err, user) {
        if (err) {
          return next(err);
        }
  
        if (!user) {
          req.session.socialProfile = info.profile;
          res.render('jade/signup/social.jade', { email: '' });
        }
        else {
          res.render('jade/signup/index.jade', {
            oauthMessage: 'We found a user linked to your Twitter account.',
            oauthTwitter: !!req.app.config.oauth.twitter.key,
            oauthGitHub: !!req.app.config.oauth.github.key,
            oauthFacebook: !!req.app.config.oauth.facebook.key,
            oauthGoogle: !!req.app.config.oauth.google.key,
            oauthTumblr: !!req.app.config.oauth.tumblr.key
          });
        }
      });
    })(req, res, next);
  };
  
  exports.signupGitHub = function(req, res, next) {
    req._passport.instance.authenticate('github', function(err, user, info) {
      if (!info || !info.profile) {
        return res.redirect('/signup/');
      }
  
      req.app.db.models.User.findOne({ 'github.id': info.profile.id }, function(err, user) {
        if (err) {
          return next(err);
        }
  
        if (!user) {
          req.session.socialProfile = info.profile;
          res.render('jade/signup/social.jade', { email: info.profile.emails && info.profile.emails[0].value || '' });
        }
        else {
          res.render('jade/signup/index.jade', {
            oauthMessage: 'We found a user linked to your GitHub account.',
            oauthTwitter: !!req.app.config.oauth.twitter.key,
            oauthGitHub: !!req.app.config.oauth.github.key,
            oauthFacebook: !!req.app.config.oauth.facebook.key,
            oauthGoogle: !!req.app.config.oauth.google.key,
            oauthTumblr: !!req.app.config.oauth.tumblr.key
          });
        }
      });
    })(req, res, next);
  };
  
  exports.signupFacebook = function(req, res, next) {
    req._passport.instance.authenticate('facebook', { callbackURL: '/signup/facebook/callback/' }, function(err, user, info) {
      if (!info || !info.profile) {
        return res.redirect('/signup/');
      }
  
      req.app.db.models.User.findOne({ 'facebook.id': info.profile.id }, function(err, user) {
        if (err) {
          return next(err);
        }
        if (!user) {
          req.session.socialProfile = info.profile;
          res.render('jade/signup/social.jade', {
            email: info.profile.emails && info.profile.emails[0].value || '',
            username: info.profile.username || '' });
        }
        else {
          res.render('jade/signup/index.jade', {
            oauthMessage: 'We found a user linked to your Facebook account.',
            oauthTwitter: !!req.app.config.oauth.twitter.key,
            oauthGitHub: !!req.app.config.oauth.github.key,
            oauthFacebook: !!req.app.config.oauth.facebook.key,
            oauthGoogle: !!req.app.config.oauth.google.key,
            oauthTumblr: !!req.app.config.oauth.tumblr.key
          });
        }
      });
    })(req, res, next);
  };
  
  exports.signupGoogle = function(req, res, next) {
    req._passport.instance.authenticate('google', { callbackURL: '/signup/google/callback/' }, function(err, user, info) {
      if (!info || !info.profile) {
        return res.redirect('/signup/');
      }
  
      req.app.db.models.User.findOne({ 'google.id': info.profile.id }, function(err, user) {
        if (err) {
          return next(err);
        }
        if (!user) {
          req.session.socialProfile = info.profile;
          res.render('jade/signup/social.jade', { email: info.profile.emails && info.profile.emails[0].value || '' });
        }
        else {
          res.render('jade/signup/index.jade', {
            oauthMessage: 'We found a user linked to your Google account.',
            oauthTwitter: !!req.app.config.oauth.twitter.key,
            oauthGitHub: !!req.app.config.oauth.github.key,
            oauthFacebook: !!req.app.config.oauth.facebook.key,
            oauthGoogle: !!req.app.config.oauth.google.key,
            oauthTumblr: !!req.app.config.oauth.tumblr.key
          });
        }
      });
    })(req, res, next);
  };
  
  exports.signupTumblr = function(req, res, next) {
    req._passport.instance.authenticate('tumblr', { callbackURL: '/signup/tumblr/callback/' }, function(err, user, info) {
      if (!info || !info.profile) {
        return res.redirect('/signup/');
      }
  
      if (!info.profile.hasOwnProperty('id')) {
        info.profile.id = info.profile.username;
      }
  
      req.app.db.models.User.findOne({ 'tumblr.id': info.profile.id }, function(err, user) {
        if (err) {
          return next(err);
        }
        if (!user) {
          req.session.socialProfile = info.profile;
          res.render('jade/signup/social.jade', { email: info.profile.emails && info.profile.emails[0].value || '' });
        }
        else {
          res.render('jade/signup/index.jade', {
            oauthMessage: 'We found a user linked to your Tumblr account.',
            oauthTwitter: !!req.app.config.oauth.twitter.key,
            oauthGitHub: !!req.app.config.oauth.github.key,
            oauthFacebook: !!req.app.config.oauth.facebook.key,
            oauthGoogle: !!req.app.config.oauth.google.key,
            oauthTumblr: !!req.app.config.oauth.tumblr.key
          });
        }
      });
    })(req, res, next);
  };
  
  exports.signupSocial = function(req, res){
    var workflow = req.app.utility.workflow(req, res);
  
    workflow.on('validate', function() {
      if (!req.body.username) {
        workflow.outcome.errfor.username = 'required';
      }
      else if (!/^[a-zA-Z0-9\_]+$/.test(req.body.username)) {
        workflow.outcome.errfor.username = 'invalid username format';
      }
      else if (!req.body.email) {
        workflow.outcome.errfor.email = 'required';
      }
      else if (!/^[a-zA-Z0-9\-\_\.\+]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z0-9\-\_]+$/.test(req.body.email)) {
        workflow.outcome.errfor.email = 'invalid email format';
      }
  
      if (workflow.hasErrors()) {
        return workflow.emit('response');
      }
  
      workflow.emit('duplicateUsernameCheck');
    });
  
    workflow.on('duplicateUsernameCheck', function() {
      workflow.username = req.body.username; //req.session.socialProfile.username || req.session.socialProfile.id;
      if (!/^[a-zA-Z0-9\_]+$/.test(workflow.username)) {
        workflow.username = workflow.username.replace(/[^a-zA-Z0-9\_]/g, '');
      }
  
      req.app.db.models.User.findOne({ username: workflow.username }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        if (user) {
          //workflow.username = workflow.username + req.session.socialProfile.id;
          workflow.outcome.errfor.username = 'username already exists';
          return workflow.emit('response');
        }
        else {
          workflow.username = workflow.username;
        }
  
        workflow.emit('duplicateEmailCheck');
      });
    });
  
    workflow.on('duplicateEmailCheck', function() {
      req.app.db.models.User.findOne({ email: req.body.email.toLowerCase() }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        if (user) {
          workflow.outcome.errfor.email = 'email already registered';
          return workflow.emit('response');
        }
  
        workflow.emit('createUser');
      });
    });
  
    workflow.on('createUser', function() {
      var fieldsToSet = {
        isActive: 'yes',
        username: workflow.username,
        email: req.body.email.toLowerCase(),
        search: [
          workflow.username,
          req.body.email
        ]
      };
      fieldsToSet[req.session.socialProfile.provider] = { id: req.session.socialProfile.id };
  
      req.app.db.models.User.create(fieldsToSet, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        workflow.user = user;
        workflow.emit('createAccount');
      });
    });
  
    workflow.on('createAccount', function() {
      var displayName = req.session.socialProfile.displayName || '';
      var nameParts = displayName.split(' ');
      var fieldsToSet = {
        isVerified: 'yes',
        'name.first': nameParts[0],
        'name.last': nameParts[1] || '',
        'name.full': displayName,
        user: {
          id: workflow.user._id,
          name: workflow.user.username
        },
        search: [
          nameParts[0],
          nameParts[1] || ''
        ]
      };
      req.app.db.models.Account.create(fieldsToSet, function(err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        //update user with account
        workflow.user.roles.account = account._id;
        workflow.user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }
  
          workflow.emit('sendWelcomeEmail');
        });
      });
    });
  
    workflow.on('sendWelcomeEmail', function() {
      req.app.utility.sendmail(req, res, {
        from: req.app.config.smtp.from.name +' <'+ req.app.config.smtp.from.address +'>',
        to: req.body.email,
        subject: 'Your '+ req.app.config.projectName +' Account',
        textPath: 'jade/signup/email-text.jade',
        htmlPath: 'jade/signup/email-html.jade',
        locals: {
          username: workflow.user.username,
          email: req.body.email,
          loginURL: req.protocol +'://'+ req.headers.host +'/login/',
          projectName: req.app.config.projectName
        },
        success: function(message) {
          workflow.emit('logUserIn');
        },
        error: function(err) {
          console.log('Error Sending Welcome Email: '+ err);
          workflow.emit('logUserIn');
        }
      });
    });
  
    workflow.on('logUserIn', function() {
      req.login(workflow.user, function(err) {
        if (err) {
          return workflow.emit('exception', err);
        }
  
        delete req.session.socialProfile;
        workflow.outcome.defaultReturnUrl = workflow.user.defaultReturnUrl();
        workflow.emit('response');
      });
    });
  
    workflow.emit('validate');
  };
  