
/* *******************************************
// Copyright 2010, Anthony Hand
//
// LICENSE INFORMATION
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
//        http://www.apache.org/licenses/LICENSE-2.0 
// Unless required by applicable law or agreed to in writing, 
// software distributed under the License is distributed on an 
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific 
// language governing permissions and limitations under the License. 
//
//
// ABOUT THIS PROJECT
//   Project Owner: Anthony Hand
//   Email: anthony.hand@gmail.com
//   Web Site: http://www.mobileesp.com
//   Source Files: http://code.google.com/p/mobileesp/
//   
//   Versions of this code are available for:
//      PHP, JavaScript, Java, and ASP.NET (C#)
//
//
// WARNING: 
//   These JavaScript-based device detection features may ONLY work 
//   for the newest generation of smartphones, such as the iPhone, 
//   Android and Palm WebOS devices.
//   These device detection features may NOT work for older smartphones 
//   which had poor support for JavaScript, including 
//   older BlackBerry, PalmOS, and Windows Mobile devices. 
//   Additionally, because JavaScript support is extremely poor among 
//   'feature phones', these features may not work at all on such devices.
//   For better results, consider using a server-based version of this code, 
//   such as Java, APS.NET, or PHP.
//
// *******************************************
*/

var MDetect = function() {
	//Optional: Store values for quickly accessing same info multiple times.
	//Stores whether the device is an iPhone or iPod Touch.
	this.isIphone = false; 
	//Stores whether is the iPhone tier of devices.
	this.isTierIphone = false; 
	//Stores whether the device can probably support Rich CSS, but JavaScript support is not assumed. (e.g., newer BlackBerry, Windows Mobile)
	this.isTierRichCss = false; 
	//Stores whether it is another mobile device, which cannot be assumed to support CSS or JS (eg, older BlackBerry, RAZR)
	this.isTierGenericMobile = false; 

	//Initialize some initial string variables we'll look for later.
	this.engineWebKit = "webkit";
	this.deviceAndroid = "android";
	this.deviceIphone = "iphone";
	this.deviceIpod = "ipod";
	this.deviceIpad = "ipad";

	this.deviceNuvifone = "nuvifone"; //Garmin Nuvifone

	this.deviceSymbian = "symbian";
	this.deviceS60 = "series60";
	this.deviceS70 = "series70";
	this.deviceS80 = "series80";
	this.deviceS90 = "series90";

	this.deviceWinMob = "windows ce";
	this.deviceWindows = "windows";
	this.deviceIeMob = "iemobile";
	this.enginePie = "wm5 pie";  //An old Windows Mobile

	this.deviceBB = "blackberry";
	this.vndRIM = "vnd.rim"; //Detectable when BB devices emulate IE or Firefox
	this.deviceBBStorm = "blackberry95"; //Storm 1 and 2
	this.deviceBBBold = "blackberry97"; //Bold
	this.deviceBBTour = "blackberry96"; //Tour
	this.deviceBBCurve = "blackberry89"; //Curve 2

	this.devicePalm = "palm";
	this.deviceWebOS = "webos"; //For Palm's new WebOS devices
	this.engineBlazer = "blazer"; //Old Palm browser
	this.engineXiino = "xiino";

	this.deviceKindle = "kindle"; //Amazon Kindle, eInk one.

	//Initialize variables for mobile-specific content.
	this.vndwap = "vnd.wap";
	this.wml = "wml";

	//Initialize variables for random devices and mobile browsers.
	//Some of these may not support JavaScript
	this.deviceBrew = "brew";
	this.deviceDanger = "danger";
	this.deviceHiptop = "hiptop";
	this.devicePlaystation = "playstation";
	this.deviceNintendoDs = "nitro";
	this.deviceNintendo = "nintendo";
	this.deviceWii = "wii";
	this.deviceXbox = "xbox";
	this.deviceArchos = "archos";

	this.engineOpera = "opera"; //Popular browser
	this.engineNetfront = "netfront"; //Common embedded OS browser
	this.engineUpBrowser = "up.browser"; //common on some phones
	this.engineOpenWeb = "openweb"; //Transcoding by OpenWave server
	this.deviceMidp = "midp"; //a mobile Java technology
	this.uplink = "up.link";
	this.engineTelecaQ = 'teleca q'; //a modern feature phone browser

	this.devicePda = "pda";
	this.mini = "mini";  //Some mobile browsers put 'mini' in their names.
	this.mobile = "mobile"; //Some mobile browsers put 'mobile' in their user agent strings.
	this.mobi = "mobi"; //Some mobile browsers put 'mobi' in their user agent strings.

	//Use Maemo, Tablet, and Linux to test for Nokia's Internet Tablets.
	this.maemo = "maemo";
	this.maemoTablet = "tablet";
	this.linux = "linux";
	this.qtembedded = "qt embedded"; //for Sony Mylo and others
	this.mylocom2 = "com2"; //for Sony Mylo also

	//In some UserAgents, the only clue is the manufacturer.
	this.manuSonyEricsson = "sonyericsson";
	this.manuericsson = "ericsson";
	this.manuSamsung1 = "sec-sgh";
	this.manuSony = "sony";

	//In some UserAgents, the only clue is the operator.
	this.svcDocomo = "docomo";
	this.svcKddi = "kddi";
	this.svcVodafone = "vodafone";


	//Initialize our user agent string.
	this.uagent = navigator.userAgent.toLowerCase();	
}

//**************************
// Detects if the current device is an iPhone.
MDetect.prototype.DetectIphone = function()
{
   if (this.uagent.search(this.deviceIphone) > -1)
   {
      //The iPod Touch says it's an iPhone! So let's disambiguate.
      if (this.uagent.search(this.deviceIpod) > -1)
         return false;
      else 
         return true;
   }
   else
      return false;
}

//**************************
// Detects if the current device is an iPod Touch.
MDetect.prototype.DetectIpod = function()
{
   if (this.uagent.search(this.deviceIpod) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current device is an iPad tablet.
MDetect.prototype.DetectIpad = function()
{
   if (this.uagent.search(this.deviceIpad) > -1  && this.DetectWebkit())
      return true;
   else
      return false;
}

//**************************
// Detects if the current device is an iPhone or iPod Touch.
MDetect.prototype.DetectIphoneOrIpod = function()
{
   //We repeat the searches here because some iPods 
   //  may report themselves as an iPhone, which is ok.
   if (this.uagent.search(this.deviceIphone) > -1 ||
       this.uagent.search(this.deviceIpod) > -1)
       return true;
    else
       return false;
}

//**************************
// Detects if the current device is an Android OS-based device.
MDetect.prototype.DetectAndroid = function()
{
   if (this.uagent.search(this.deviceAndroid) > -1)
      return true;
   else
      return false;
}


//**************************
// Detects if the current device is an Android OS-based device and
//   the browser is based on WebKit.
MDetect.prototype.DetectAndroidWebKit = function()
{
   if (this.DetectAndroid() && this.DetectWebkit())
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is based on WebKit.
MDetect.prototype.DetectWebkit = function()
{
   if (this.uagent.search(this.engineWebKit) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is the Nokia S60 Open Source Browser.
MDetect.prototype.DetectS60OssBrowser = function()
{
   if (this.DetectWebkit())
   {
     if ((this.uagent.search(this.deviceS60) > -1 || 
          this.uagent.search(this.deviceSymbian) > -1))
        return true;
     else
        return false;
   }
   else
      return false;
}

//**************************
// Detects if the current device is any Symbian OS-based device,
//   including older S60, Series 70, Series 80, Series 90, and UIQ, 
//   or other browsers running on these devices.
MDetect.prototype.DetectSymbianOS = function()
{
   if (this.uagent.search(this.deviceSymbian) > -1 ||
       this.uagent.search(this.deviceS60) > -1 ||
       this.uagent.search(this.deviceS70) > -1 ||
       this.uagent.search(this.deviceS80) > -1 ||
       this.uagent.search(this.deviceS90) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a Windows Mobile device.
MDetect.prototype.DetectWindowsMobile = function()
{
   //Most devices use 'Windows CE', but some report 'iemobile' 
   //  and some older ones report as 'PIE' for Pocket IE. 
   if (this.uagent.search(this.deviceWinMob) > -1 ||
       this.uagent.search(this.deviceIeMob) > -1 ||
       this.uagent.search(this.enginePie) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a BlackBerry of some sort.
MDetect.prototype.DetectBlackBerry = function()
{
   if (this.uagent.search(this.deviceBB) > -1)
      return true;
   if (this.uagent.search(this.vndRIM) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a BlackBerry Touch
//    device, such as the Storm.
MDetect.prototype.DetectBlackBerryTouch = function()
{
   if (this.uagent.search(this.deviceBBStorm) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a BlackBerry device AND
//    has a more capable recent browser. 
//    Examples, Storm, Bold, Tour, Curve2
MDetect.prototype.DetectBlackBerryHigh = function()
{
   if (this.DetectBlackBerry())
   {
     if (this.DetectBlackBerryTouch() ||
        this.uagent.search(this.deviceBBBold) > -1 || 
        this.uagent.search(this.deviceBBTour) > -1 || 
        this.uagent.search(this.deviceBBCurve) > -1)
        return true;
     else
        return false;
   }
   else
      return false;
}

//**************************
// Detects if the current browser is a BlackBerry device AND
//    has an older, less capable browser. 
//    Examples: Pearl, 8800, Curve1.
MDetect.prototype.DetectBlackBerryLow = function()
{
   if (this.DetectBlackBerry())
   {
     //Assume that if it's not in the High tier, then it's Low.
     if (this.DetectBlackBerryHigh())
        return false;
     else
        return true;
   }
   else
      return false;
}


//**************************
// Detects if the current browser is on a PalmOS device.
MDetect.prototype.DetectPalmOS = function()
{
   //Most devices nowadays report as 'Palm', 
   //  but some older ones reported as Blazer or Xiino.
   if (this.uagent.search(this.devicePalm) > -1 ||
       this.uagent.search(this.engineBlazer) > -1 ||
       this.uagent.search(this.engineXiino) > -1)
   {
     //Make sure it's not WebOS first
     if (this.DetectPalmWebOS())
        return false;
     else
        return true;
   }
   else
      return false;
}

//**************************
// Detects if the current browser is on a Palm device
//   running the new WebOS.
MDetect.prototype.DetectPalmWebOS = function()
{
   if (this.uagent.search(this.deviceWebOS) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a
//   Garmin Nuvifone.
MDetect.prototype.DetectGarminNuvifone = function()
{
   if (this.uagent.search(this.deviceNuvifone) > -1)
      return true;
   else
      return false;
}


//**************************
// Check to see whether the device is a 'smartphone'.
//   You might wish to send smartphones to a more capable web page
//   than a dumbed down WAP page. 
MDetect.prototype.DetectSmartphone = function()
{
   if (this.DetectIphoneOrIpod())
      return true;
   if (this.DetectS60OssBrowser())
      return true;
   if (this.DetectSymbianOS())
      return true;
   if (this.DetectWindowsMobile())
      return true;
   if (this.DetectAndroid())
      return true;
   if (this.DetectBlackBerry())
      return true;
   if (this.DetectPalmWebOS())
      return true;
   if (this.DetectPalmOS())
      return true;
   if (this.DetectGarminNuvifone())
      return true;

   //Otherwise, return false.
   return false;
};

//**************************
// Detects if the current device is an Archos media player/Internet tablet.
MDetect.prototype.DetectArchos = function()
{
   if (this.uagent.search(this.deviceArchos) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects whether the device is a Brew-powered device.
MDetect.prototype.DetectBrewDevice = function()
{
   if (this.uagent.search(this.deviceBrew) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects the Danger Hiptop device.
MDetect.prototype.DetectDangerHiptop = function()
{
   if (this.uagent.search(this.deviceDanger) > -1 ||
       this.uagent.search(this.deviceHiptop))
      return true;
   else
      return false;
}

//**************************
// Detects if the current device is on one of 
// the Maemo-based Nokia Internet Tablets.
MDetect.prototype.DetectMaemoTablet = function()
{
   if (this.uagent.search(this.maemo) > -1)
      return true;
   //Must be Linux + Tablet, or else it could be something else.
   if (this.uagent.search(this.maemoTablet) > -1 &&
       this.uagent.search(this.linux))
      return true;
   else
      return false;
}

//**************************
// Detects if the current browser is a Sony Mylo device.
MDetect.prototype.DetectSonyMylo = function()
{
   if (this.uagent.search(this.manuSony) > -1)
   {
     if (this.uagent.search(this.qtembedded) > -1 ||
         this.uagent.search(this.mylocom2) > -1)
        return true;
     else
        return false;
   }
   else
      return false;
}

//**************************
// Detects if the current browser is Opera Mobile or Mini.
MDetect.prototype.DetectOperaMobile = function()
{
   if (this.uagent.search(this.engineOpera) > -1)
   {
     if (this.uagent.search(this.mini) > -1 ||
         this.uagent.search(this.mobi) > -1)
        return true;
     else
        return false;
   }
   else
      return false;
}

//**************************
// Detects if the current device is a Sony Playstation.
MDetect.prototype.DetectSonyPlaystation = function()
{
   if (this.uagent.search(this.devicePlaystation))
      return true;
   else
      return false;
};

//**************************
// Detects if the current device is a Nintendo game device.
MDetect.prototype.DetectNintendo = function()
{
   if (this.uagent.search(this.deviceNintendo) > -1   || 
	this.uagent.search(this.deviceWii) > -1 ||
	this.uagent.search(this.deviceNintendoDs) > -1)
      return true;
   else
      return false;
};

//**************************
// Detects if the current device is a Microsoft Xbox.
MDetect.prototype.DetectXbox = function()
{
   if (this.uagent.search(this.deviceXbox))
      return true;
   else
      return false;
};

//**************************
// Detects if the current device is an Internet-capable game console.
MDetect.prototype.DetectGameConsole = function()
{
   if (this.DetectSonyPlaystation())
      return true;
   if (this.DetectNintendo())
      return true;
   if (this.DetectXbox())
      return true;
   else
      return false;
};

//**************************
// Detects if the current device is a Kindle.
MDetect.prototype.DetectKindle = function()
{
   if (this.uagent.search(this.deviceKindle) > -1)
      return true;
   else
      return false;
}

//**************************
// Detects if the current device is a mobile device.
//  This method catches most of the popular modern devices.
MDetect.prototype.DetectMobileQuick = function()
{
   //Most mobile browsing is done on smartphones
   if (this.DetectSmartphone())
      return true;

   if (this.uagent.search(this.deviceWap) > -1   || 
	this.uagent.search(this.deviceMidp) > -1 ||
	this.uagent.search(this.deviceWml) > -1  ||
	this.DetectBrewDevice())
      return true;

   if (this.DetectOperaMobile())
      return true;

   if (this.uagent.search(this.engineNetfront) > -1)
      return true;
   if (this.uagent.search(this.engineUpBrowser) > -1)
      return true;
   if (this.uagent.search(this.engineOpenWeb) > -1)
      return true;

   if (this.DetectDangerHiptop())
      return true;
      
   if (this.DetectMaemoTablet())
      return true;
   if (this.DetectArchos())
      return true;

   if (this.uagent.search(this.devicePda) > -1)
      return true;
   if (this.uagent.search(this.mobile) > -1)
      return true;

   if (this.DetectKindle())
      return true;
      
   return false;
};


//**************************
// Detects in a more comprehensive way if the current device is a mobile device.
MDetect.prototype.DetectMobileLong = function()
{
   if (this.DetectMobileQuick())
      return true;
   if (this.DetectGameConsole())
      return true;
   if (this.DetectSonyMylo())
      return true;

   //Detect for certain very old devices with stupid useragent strings.
   if (this.uagent.search(this.manuSamsung1) > -1 ||
	this.uagent.search(this.manuSonyEricsson) > -1 || 
	this.uagent.search(this.manuericsson) > -1)
      return true;

   if (this.uagent.search(this.svcDocomo) > -1)
      return true;
   if (this.uagent.search(this.svcKddi) > -1)
      return true;
   if (this.uagent.search(this.svcVodafone) > -1)
      return true;


   return false;
};


//*****************************
// For Mobile Web Site Design
//*****************************

//**************************
// The quick way to detect for a tier of devices.
//   This method detects for devices which can 
//   display iPhone-optimized web content.
//   Includes iPhone, iPod Touch, Android, WebOS, etc.
MDetect.prototype.DetectTierIphone = function()
{
   if (this.DetectIphoneOrIpod())
      return true;
   if (this.DetectAndroid())
      return true;
   if (this.DetectAndroidWebKit())
      return true;
   if (this.DetectPalmWebOS())
      return true;
   if (this.DetectGarminNuvifone())
      return true;
   if (this.DetectMaemoTablet())
      return true;
   if (this.DetectIpad())
      return true;
   else
      return false;
};

//**************************
// The quick way to detect for a tier of devices.
//   This method detects for devices which are likely to be 
//   capable of viewing CSS content optimized for the iPhone, 
//   but may not necessarily support JavaScript.
//   Excludes all iPhone Tier devices.
MDetect.prototype.DetectTierRichCss = function()
{
    if (this.DetectMobileQuick())
    {
       if (this.DetectTierIphone())
          return false;
          
       //The following devices are explicitly ok.
       if (this.DetectWebkit())
          return true;
       if (this.DetectS60OssBrowser())
          return true;

       //Note: 'High' BlackBerry devices ONLY
       if (this.DetectBlackBerryHigh())
          return true;

       if (this.DetectWindowsMobile())
          return true;
          
       if (this.uagent.search(this.engineTelecaQ) > -1)
          return true;
          
       else
          return false;
    }
    else
      return false;
};

//**************************
// The quick way to detect for a tier of devices.
//   This method detects for all other types of phones,
//   but excludes the iPhone and RichCSS Tier devices.
// NOTE: This method probably won't work due to poor
//  support for JavaScript among other devices. 
MDetect.prototype.DetectTierOtherPhones = function()
{
    if (this.DetectMobileLong())
    {
       //Exclude devices in the other 2 categories
       if (this.DetectTierIphone())
          return false;
       if (this.DetectTierRichCss())
          return false;

       //Otherwise, it's a YES
       else
          return true;
    }
    else
      return false;
};

