diff --git a/INSTALL.txt b/INSTALL.txt
index 056b2b0..d7636f5 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -1,4 +1,3 @@
-
 Database Files
 --------------------
 Before using this module, you will need to:
diff --git a/geoip.admin.inc b/geoip.admin.inc
index 41cdbd5..cf7c9c6 100644
--- a/geoip.admin.inc
+++ b/geoip.admin.inc
@@ -44,4 +44,3 @@ function geoip_data_file_validate($form_element) {
 
   return $form_element;
 }
-
diff --git a/geoip.info b/geoip.info
index af07ef8..b851232 100644
--- a/geoip.info
+++ b/geoip.info
@@ -1,3 +1,13 @@
 name = GeoIP
 description = API for using the MaxMind GeoLite Country database
-core = 6.x
+core = 7.x
+
+files[] = geoip.admin.inc
+files[] = geoip.install
+files[] = geoip.module
+files[] = geoip.values.inc
+files[] = lib/geoip.inc
+files[] = lib/geoipcity.inc
+files[] = lib/geoipregionvars.php
+files[] = geoip.tokens.inc
+files[] = geoip.rules.inc
diff --git a/geoip.install b/geoip.install
index 0c05ae2..1ad758f 100644
--- a/geoip.install
+++ b/geoip.install
@@ -8,9 +8,11 @@
 /**
  * We're changing the default path. If it's been working for them make sure
  * it is set and not relying on the default value.
+ *
+ * @return array
  */
 function geoip_update_6000() {
-  $previous_path = variable_get('geoip_data_file', drupal_get_path('module', 'geoip') .'/data/GeoIP.dat');
+  $previous_path = variable_get('geoip_data_file', drupal_get_path('module', 'geoip') . '/data/GeoIP.dat');
   if (isset($previous_path) && file_exists($previous_path)) {
     variable_set('geoip_data_file', $previous_path);
   }
diff --git a/geoip.module b/geoip.module
index 062b25a..2620f02 100644
--- a/geoip.module
+++ b/geoip.module
@@ -6,10 +6,12 @@
  */
 
 /**
- * Implementation of hook_menu().
+ * Implements hook_menu().
+ *
+ * @return array
  */
 function geoip_menu() {
-  $items['admin/settings/geoip'] = array(
+  $items['admin/config/system/geoip'] = array(
     'title' => 'GeoIP',
     'description' => 'Configure the path to the GeoIP database.',
     'page callback' => 'drupal_get_form',
@@ -22,7 +24,10 @@ function geoip_menu() {
 }
 
 /**
- * Implementation of hook_requirements().
+ * Implements hook_requirements().
+ *
+ * @param string $phase
+ * @return array
  */
 function geoip_requirements($phase) {
   $requirements = array();
@@ -58,6 +63,8 @@ function geoip_requirements($phase) {
 
 /**
  * Helper function to get the current ip address
+ *
+ * @return string
  */
 function geoip_ip_address() {
   if (variable_get('geoip_debug', FALSE) && !empty($_GET['geoip_debug'])) {
@@ -95,6 +102,8 @@ function geoip_instance() {
  * Get the file path of the geoip module.  This is a wrapper around
  * drupal_get_path() that falls back to simply using the directory of the
  * module file if too early in the bootstrap.
+ *
+ * @return string
  */
 function geoip_get_path() {
   if (function_exists('drupal_get_path')) {
@@ -111,6 +120,8 @@ function geoip_get_path() {
 
 /**
  * Return the path of the GeoIP.dat data file.
+ *
+ * @return string
  */
 function geoip_data_file() {
   return variable_get('geoip_data_file', 'sites/all/libraries/geoip/GeoIP.dat');
@@ -119,7 +130,7 @@ function geoip_data_file() {
 /**
  * Include the external geoip libraries.
  *
- * @param
+ * @param $file
  *   The file to be included.  Must reside in the lib sub-directory.
  */
 function _geoip_load_lib($file = 'geoip.inc') {
@@ -129,7 +140,7 @@ function _geoip_load_lib($file = 'geoip.inc') {
   // through.
   if (!isset($loaded[$file])) {
     $loaded[$file] = TRUE;
-    include_once(geoip_get_path() . '/lib/'. $file);
+    include_once geoip_get_path() . '/lib/' . $file;
   }
 }
 
@@ -143,6 +154,9 @@ function _geoip_load_lib($file = 'geoip.inc') {
  * API function to return the country code for a given IP. Defaults to using the
  * current user's IP if not specified. This function works with both the country
  * and city level databases.
+ *
+ * @return string
+ *  Country Code
  */
 function geoip_country_code($ip = NULL) {
   $ip = $ip ? $ip : geoip_ip_address();
@@ -197,18 +211,25 @@ function geoip_city($ip = NULL) {
  * API function to retrieve the region name, given a country code and region
  * code. This function relies on the geoipregionvars.php file, which is just a
  * huge array.
+ *
+ * @return string
  */
 function geoip_region_name($country_code, $region_code) {
   static $GEOIP_REGION_NAME;
   if (!isset($GEOIP_REGION_NAME)) {
-    include drupal_get_path('module', 'geoip') .'/lib/geoipregionvars.php';
+    include drupal_get_path('module', 'geoip') . '/lib/geoipregionvars.php';
   }
 
   return $GEOIP_REGION_NAME[$country_code][$region_code];
 }
 
 /**
- * Return a list of country codes as specified by http://www.maxmind.com/app/iso3166
+ * Returns a list of country codes.
+ *
+ * Returns codes as specified by http://www.maxmind.com/app/iso3166
+ *
+ * @return array
+ *  Associative array with the country code as key, and the country name as value.
  */
 function geoip_country_values() {
   static $countries = NULL;
diff --git a/geoip.values.inc b/geoip.values.inc
index f962999..9df0c20 100644
--- a/geoip.values.inc
+++ b/geoip.values.inc
@@ -2,261 +2,28 @@
 
 /**
  * @file
- * file_description
+ * Helper functions to fetch basic values
  */
 
 /**
- * Return a list of country codes as specified by http://www.maxmind.com/app/iso3166
+ * Return a list of country codes.
+ *
+ * List consists of iso3166 codes and the maxmind special codes
+ * defined here: http://www.maxmind.com/app/iso3166
+ *
+ * @return array
  */
 function _geoip_country_values() {
-  return array(
-    'A1' => "Anonymous Proxy",
-    'A2' => "Satellite Provider",
-    'AD' => "Andorra",
-    'AE' => "United Arab Emirates",
-    'AF' => "Afghanistan",
-    'AG' => "Antigua and Barbuda",
-    'AI' => "Anguilla",
-    'AL' => "Albania",
-    'AM' => "Armenia",
-    'AN' => "Netherlands Antilles",
-    'AO' => "Angola",
-    'AP' => "Asia/Pacific Region",
-    'AQ' => "Antarctica",
-    'AR' => "Argentina",
-    'AS' => "American Samoa",
-    'AT' => "Austria",
-    'AU' => "Australia",
-    'AW' => "Aruba",
-    'AX' => "Aland Islands",
-    'AZ' => "Azerbaijan",
-    'BA' => "Bosnia and Herzegovina",
-    'BB' => "Barbados",
-    'BD' => "Bangladesh",
-    'BE' => "Belgium",
-    'BF' => "Burkina Faso",
-    'BG' => "Bulgaria",
-    'BH' => "Bahrain",
-    'BI' => "Burundi",
-    'BJ' => "Benin",
-    'BM' => "Bermuda",
-    'BN' => "Brunei Darussalam",
-    'BO' => "Bolivia",
-    'BR' => "Brazil",
-    'BS' => "Bahamas",
-    'BT' => "Bhutan",
-    'BV' => "Bouvet Island",
-    'BW' => "Botswana",
-    'BY' => "Belarus",
-    'BZ' => "Belize",
-    'CA' => "Canada",
-    'CC' => "Cocos (Keeling) Islands",
-    'CD' => "Congo, The Democratic Republic of the",
-    'CF' => "Central African Republic",
-    'CG' => "Congo",
-    'CH' => "Switzerland",
-    'CI' => "Cote d'Ivoire",
-    'CK' => "Cook Islands",
-    'CL' => "Chile",
-    'CM' => "Cameroon",
-    'CN' => "China",
-    'CO' => "Colombia",
-    'CR' => "Costa Rica",
-    'CU' => "Cuba",
-    'CV' => "Cape Verde",
-    'CX' => "Christmas Island",
-    'CY' => "Cyprus",
-    'CZ' => "Czech Republic",
-    'DE' => "Germany",
-    'DJ' => "Djibouti",
-    'DK' => "Denmark",
-    'DM' => "Dominica",
-    'DO' => "Dominican Republic",
-    'DZ' => "Algeria",
-    'EC' => "Ecuador",
-    'EE' => "Estonia",
-    'EG' => "Egypt",
-    'EH' => "Western Sahara",
-    'ER' => "Eritrea",
-    'ES' => "Spain",
-    'ET' => "Ethiopia",
-    'EU' => "Europe",
-    'FI' => "Finland",
-    'FJ' => "Fiji",
-    'FK' => "Falkland Islands (Malvinas)",
-    'FM' => "Micronesia, Federated States of",
-    'FO' => "Faroe Islands",
-    'FR' => "France",
-    'GA' => "Gabon",
-    'GB' => "United Kingdom",
-    'GD' => "Grenada",
-    'GE' => "Georgia",
-    'GF' => "French Guiana",
-    'GG' => "Guernsey",
-    'GH' => "Ghana",
-    'GI' => "Gibraltar",
-    'GL' => "Greenland",
-    'GM' => "Gambia",
-    'GN' => "Guinea",
-    'GP' => "Guadeloupe",
-    'GQ' => "Equatorial Guinea",
-    'GR' => "Greece",
-    'GS' => "South Georgia and the South Sandwich Islands",
-    'GT' => "Guatemala",
-    'GU' => "Guam",
-    'GW' => "Guinea-Bissau",
-    'GY' => "Guyana",
-    'HK' => "Hong Kong",
-    'HM' => "Heard Island and McDonald Islands",
-    'HN' => "Honduras",
-    'HR' => "Croatia",
-    'HT' => "Haiti",
-    'HU' => "Hungary",
-    'ID' => "Indonesia",
-    'IE' => "Ireland",
-    'IL' => "Israel",
-    'IM' => "Isle of Man",
-    'IN' => "India",
-    'IO' => "British Indian Ocean Territory",
-    'IQ' => "Iraq",
-    'IR' => "Iran, Islamic Republic of",
-    'IS' => "Iceland",
-    'IT' => "Italy",
-    'JE' => "Jersey",
-    'JM' => "Jamaica",
-    'JO' => "Jordan",
-    'JP' => "Japan",
-    'KE' => "Kenya",
-    'KG' => "Kyrgyzstan",
-    'KH' => "Cambodia",
-    'KI' => "Kiribati",
-    'KM' => "Comoros",
-    'KN' => "Saint Kitts and Nevis",
-    'KP' => "Korea, Democratic People's Republic of",
-    'KR' => "Korea, Republic of",
-    'KW' => "Kuwait",
-    'KY' => "Cayman Islands",
-    'KZ' => "Kazakhstan",
-    'LA' => "Lao People's Democratic Republic",
-    'LB' => "Lebanon",
-    'LC' => "Saint Lucia",
-    'LI' => "Liechtenstein",
-    'LK' => "Sri Lanka",
-    'LR' => "Liberia",
-    'LS' => "Lesotho",
-    'LT' => "Lithuania",
-    'LU' => "Luxembourg",
-    'LV' => "Latvia",
-    'LY' => "Libyan Arab Jamahiriya",
-    'MA' => "Morocco",
-    'MC' => "Monaco",
-    'MD' => "Moldova, Republic of",
-    'ME' => "Montenegro",
-    'MG' => "Madagascar",
-    'MH' => "Marshall Islands",
-    'MK' => "Macedonia",
-    'ML' => "Mali",
-    'MM' => "Myanmar",
-    'MN' => "Mongolia",
-    'MO' => "Macao",
-    'MP' => "Northern Mariana Islands",
-    'MQ' => "Martinique",
-    'MR' => "Mauritania",
-    'MS' => "Montserrat",
-    'MT' => "Malta",
-    'MU' => "Mauritius",
-    'MV' => "Maldives",
-    'MW' => "Malawi",
-    'MX' => "Mexico",
-    'MY' => "Malaysia",
-    'MZ' => "Mozambique",
-    'NA' => "Namibia",
-    'NC' => "New Caledonia",
-    'NE' => "Niger",
-    'NF' => "Norfolk Island",
-    'NG' => "Nigeria",
-    'NI' => "Nicaragua",
-    'NL' => "Netherlands",
-    'NO' => "Norway",
-    'NP' => "Nepal",
-    'NR' => "Nauru",
-    'NU' => "Niue",
-    'NZ' => "New Zealand",
-    'OM' => "Oman",
-    'PA' => "Panama",
-    'PE' => "Peru",
-    'PF' => "French Polynesia",
-    'PG' => "Papua New Guinea",
-    'PH' => "Philippines",
-    'PK' => "Pakistan",
-    'PL' => "Poland",
-    'PM' => "Saint Pierre and Miquelon",
-    'PN' => "Pitcairn",
-    'PR' => "Puerto Rico",
-    'PS' => "Palestinian Territory",
-    'PT' => "Portugal",
-    'PW' => "Palau",
-    'PY' => "Paraguay",
-    'QA' => "Qatar",
-    'RE' => "Reunion",
-    'RO' => "Romania",
-    'RS' => "Serbia",
-    'RU' => "Russian Federation",
-    'RW' => "Rwanda",
-    'SA' => "Saudi Arabia",
-    'SB' => "Solomon Islands",
-    'SC' => "Seychelles",
-    'SD' => "Sudan",
-    'SE' => "Sweden",
-    'SG' => "Singapore",
-    'SH' => "Saint Helena",
-    'SI' => "Slovenia",
-    'SJ' => "Svalbard and Jan Mayen",
-    'SK' => "Slovakia",
-    'SL' => "Sierra Leone",
-    'SM' => "San Marino",
-    'SN' => "Senegal",
-    'SO' => "Somalia",
-    'SR' => "Suriname",
-    'ST' => "Sao Tome and Principe",
-    'SV' => "El Salvador",
-    'SY' => "Syrian Arab Republic",
-    'SZ' => "Swaziland",
-    'TC' => "Turks and Caicos Islands",
-    'TD' => "Chad",
-    'TF' => "French Southern Territories",
-    'TG' => "Togo",
-    'TH' => "Thailand",
-    'TJ' => "Tajikistan",
-    'TK' => "Tokelau",
-    'TL' => "Timor-Leste",
-    'TM' => "Turkmenistan",
-    'TN' => "Tunisia",
-    'TO' => "Tonga",
-    'TR' => "Turkey",
-    'TT' => "Trinidad and Tobago",
-    'TV' => "Tuvalu",
-    'TW' => "Taiwan",
-    'TZ' => "Tanzania, United Republic of",
-    'UA' => "Ukraine",
-    'UG' => "Uganda",
-    'UM' => "United States Minor Outlying Islands",
-    'US' => "United States",
-    'UY' => "Uruguay",
-    'UZ' => "Uzbekistan",
-    'VA' => "Holy See (Vatican City State)",
-    'VC' => "Saint Vincent and the Grenadines",
-    'VE' => "Venezuela",
-    'VG' => "Virgin Islands, British",
-    'VI' => "Virgin Islands, U.S.",
-    'VN' => "Vietnam",
-    'VU' => "Vanuatu",
-    'WF' => "Wallis and Futuna",
-    'WS' => "Samoa",
-    'YE' => "Yemen",
-    'YT' => "Mayotte",
-    'ZA' => "South Africa",
-    'ZM' => "Zambia",
-    'ZW' => "Zimbabwe",
+  include_once DRUPAL_ROOT . '/includes/locale.inc';
+  $countries = country_get_list();
+
+  // MaxMind specific shortcuts
+  $countries += array(
+    'A1' => t('Anonymous Proxy'),
+    'A2' => t('Satellite Provider'),
+    'AP' => t('Asia/Pacific Region'),
+    'EU' => t('Europe'),
+    'O1' => t('Other Country'),
   );
+  return $countries;
 }
diff --git a/geoip_language/geoip_language.admin.inc b/geoip_language/geoip_language.admin.inc
index d6f3490..9e13902 100644
--- a/geoip_language/geoip_language.admin.inc
+++ b/geoip_language/geoip_language.admin.inc
@@ -6,25 +6,31 @@
  */
 
 /**
- * Menu callback for admin/settings/language/geoip
+ * Create the overview table of the already existing mappgins
+ *
+ * @param array $languages
+ * @return string
+ *  HTML Table
  */
-function geoip_language_settings_overview() {
-  if (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) != GEOIP_LANGUAGE_NEGOTIATION_PATH) {
-    drupal_set_message(t('The GeoIP settings will have no effect until <em>Language Negotiation</em> is set to <em>Path prefix with GeoIP detection fallback</em> on the <a href="@language-configure">Language configuration page</a>.', array('@language-configure' => url('admin/settings/language/configure'))), 'warning');
-  }
+function theme_geoip_language_mapping_overview($languages) {
 
   $countries = geoip_country_values();
-  $languages = locale_language_list('name', TRUE);
-  $mapping = geoip_language_mappings();
+  $mapping = geoip_language_mappings(TRUE);
+
+  $output = NULL;
 
   $rows = array();
-  foreach ($mapping as $country => $info) {
+  foreach ($mapping as $country => $language) {
     $rows[] = array(
       $country,
       $countries[$country],
-      $info->language,
-      $languages[$info->language],
-      l(t('Delete'), 'admin/settings/language/geoip/delete/'. $country, array('query' => drupal_get_destination())),
+      $language,
+      $languages[$language],
+      l(
+        t('Delete'),
+        'admin/config/regional/language/configure/geoip/delete/' . $country,
+        array('query' => drupal_get_destination())
+      ),
     );
   }
   if (count($rows)) {
@@ -33,22 +39,33 @@ function geoip_language_settings_overview() {
       array('data' => t('Language'), 'colspan' => 2),
       t('Operations'),
     );
-    $output .= theme('table', $header, $rows);
+    $output .= theme_table(
+      array(
+        'header' => $header,
+        'rows' => $rows,
+        'attributes' => array(),
+        'caption' => NULL,
+        'colgroups' => NULL,
+        'sticky' => TRUE,
+        'empty' => t('No GeoIP language mappings defined.'),
+      )
+    );
   }
   else {
     drupal_set_message(t('No GeoIP language mappings defined.'));
   }
-
-  $output .= drupal_get_form('geoip_language_settings_form');
   return $output;
 }
 
 /**
  * FAPI callback for creating a new country-language mapping.
+ *
+ * @return array
  */
-function geoip_language_settings_form() {
+function geoip_language_form($form, &$form_state) {
   $countries = geoip_country_values();
-  $mapping = geoip_language_mappings();
+  $mapping = geoip_language_mappings(TRUE);
+  $languages = locale_language_list('name', TRUE);
   $options = array();
   foreach ($countries as $key => $value) {
     if (!$mapping[$key]) {
@@ -69,7 +86,7 @@ function geoip_language_settings_form() {
   $form['new']['language'] = array(
     '#type' => 'select',
     '#title' => t('Language'),
-    '#options' => locale_language_list('name', TRUE),
+    '#options' => $languages,
   );
 
   $form['new']['buttons'] = array();
@@ -78,41 +95,57 @@ function geoip_language_settings_form() {
     '#value' => t('Add mapping'),
   );
 
+  $form['set3']['textfiles'] = array(
+    '#type' => 'item',
+    '#markup' => theme('geoip_language_mapping_overview', $languages),
+  );
+
   return $form;
 }
 
 /**
  * FAPI submit handler.
  */
-function geoip_language_settings_form_submit($form, &$form_state) {
-  geoip_language_mapping_create($form_state['values']['country'], $form_state['values']['language']);
+function geoip_language_form_submit($form, &$form_state) {
+  geoip_language_mapping_create(
+    $form_state['values']['country'],
+    $form_state['values']['language']
+  );
 
   $countries = geoip_country_values();
   drupal_set_message(t('GeoIP mapping created for %country.', array('%country' => $countries[$form_state['values']['country']])));
 
-  $form_state['redirect'] = 'admin/settings/language/geoip';
+  $form_state['redirect'] = 'admin/config/regional/language/configure/geoip';
 }
 
+/**
+ * Create th confirm form for deleting a mapping item
+ */
 function geoip_admin_delete_mapping(&$form_state, $country) {
   $form['country'] = array(
     '#type' => 'value',
     '#value' => $country,
   );
 
-  return confirm_form($form,
+  return confirm_form(
+    $form,
     t('Are you sure you want to delete this mapping?'),
-    isset($_GET['destination']) ? $_GET['destination'] : 'admin/settings/language/geoip',
+    isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/regional/language/configure/geoip',
     t('This action cannot be undone.'),
     t('Delete'),
     t('Cancel')
   );
 }
 
+/**
+ * Process a confirmed delete request of a mapping item
+ */
 function geoip_admin_delete_mapping_submit($form, &$form_state) {
-  geoip_language_mapping_delete($form_state['values']['country']);
+  $coutry_code = $form_state['values']['country']['build_info']['args'][0];
+  geoip_language_mapping_delete($coutry_code);
 
   $countries = geoip_country_values();
-  drupal_set_message(t('GeoIP mapping deleted for %country.', array('%country' => $countries[$form_state['values']['country']])));
+  drupal_set_message(t('GeoIP mapping deleted for %country.', array('%country' => $countries[$coutry_code])));
 
-  $form_state['redirect'] = 'admin/settings/language/geoip';
-}
\ No newline at end of file
+  $form_state['redirect'] = 'admin/config/regional/language/configure/geoip';
+}
diff --git a/geoip_language/geoip_language.fastpath.inc b/geoip_language/geoip_language.fastpath.inc
index d5d4a01..5804f70 100644
--- a/geoip_language/geoip_language.fastpath.inc
+++ b/geoip_language/geoip_language.fastpath.inc
@@ -5,8 +5,11 @@
  * description
  */
 
+/**
+ * Some sort of caching.
+ */
 function page_cache_fastpath() {
-  $file = variable_get('file_directory_path', conf_path() .'/files') .'/geoip_language.txt';
+  $file = variable_get('file_directory_path', conf_path() . '/files') . '/geoip_language.txt';
   if (file_exists($file)) {
     $data = unserialize(file_get_contents($file));
     $mapping = isset($data['geoip']) ? $data['geoip'] : NULL;
@@ -21,12 +24,12 @@ function page_cache_fastpath() {
     global $base_path;
 
     // no language prefix; geoip detect, then redirect.
-    include_once dirname(dirname(__FILE__)) .'/geoip.module';
+    include_once dirname(dirname(__FILE__)) . '/geoip.module';
     $country = geoip_country_code();
     $prefix = ($country && isset($mapping[$country])) ? $mapping[$country] : $data['default'];
-    header('Location: '. $base_path . $prefix .'/'. $_GET['q']);
+    header('Location: ' . $base_path . $prefix . '/' . $_GET['q']);
     exit();
   }
 
   return FALSE;
-}
\ No newline at end of file
+}
diff --git a/geoip_language/geoip_language.info b/geoip_language/geoip_language.info
index 9690c82..23c7402 100644
--- a/geoip_language/geoip_language.info
+++ b/geoip_language/geoip_language.info
@@ -1,5 +1,10 @@
 name = GeoIP Language
 description = Language negotiation based on GeoIP detection.
-core = 6.x
+core = 7.x
 dependencies[] = locale
 dependencies[] = geoip
+
+files[] = geoip_language.admin.inc
+files[] = geoip_language.fastpath.inc
+files[] = geoip_language.install
+files[] = geoip_language.module
diff --git a/geoip_language/geoip_language.install b/geoip_language/geoip_language.install
index 515a034..ddfb7cd 100644
--- a/geoip_language/geoip_language.install
+++ b/geoip_language/geoip_language.install
@@ -6,7 +6,9 @@
  */
 
 /**
- * Implementation of hook_schema().
+ * Implements hook_schema().
+ *
+ * @return array
  */
 function geoip_language_schema() {
   $schema['geoip_language'] = array(
@@ -32,18 +34,18 @@ function geoip_language_schema() {
 }
 
 /**
- * Implementation of hook_install().
+ * Implements hook_disable().
  */
-function geoip_language_install() {
-  drupal_install_schema('geoip_language');
-  // Make sure this module loads before most "normal" modules.  This allows the
-  // language negotiation to happen in hook_init() rather than hook_boot().
-  db_query("UPDATE {system} SET weight = -1 WHERE name = 'geoip_language'");
-}
-
-/**
- * Implementation of hook_uninstall().
- */
-function geoip_language_uninstall() {
-  drupal_uninstall_schema('geoip_language');
+function geoip_language_disable() {
+  $language_negotiation = variable_get('language_negotiation_language', array());
+  if (isset($language_negotiation[GEOIP_LANGUAGE_NEGOTIATION])) {
+    unset($language_negotiation[GEOIP_LANGUAGE_NEGOTIATION]);
+    variable_set('language_negotiation_language', $language_negotiation);
+  }
+  $providers_weight_language = variable_get('locale_language_providers_weight_language', array());
+  if (isset($providers_weight_language[GEOIP_LANGUAGE_NEGOTIATION])) {
+    unset($providers_weight_language[GEOIP_LANGUAGE_NEGOTIATION]);
+    variable_set('locale_language_providers_weight_language', $providers_weight_language);
+  }
+  cache_clear_all('geoip_language_mappings', 'cache');
 }
diff --git a/geoip_language/geoip_language.module b/geoip_language/geoip_language.module
index 721924f..6d109da 100644
--- a/geoip_language/geoip_language.module
+++ b/geoip_language/geoip_language.module
@@ -7,38 +7,51 @@
 
 /**
  * Language negotiation option for GeoIP detection.
+ *
+ * @var integer
  */
 define('GEOIP_LANGUAGE_NEGOTIATION_PATH', 8);
 
 /**
- * Implementation of hook_help().
+ * Key to recognize this language provider.
+ *
+ * @var string
+ */
+define('GEOIP_LANGUAGE_NEGOTIATION', 'geoip-language-negotiation');
+
+/**
+ * Implements hook_help().
+ *
+ * @return string
  */
 function geoip_language_help($path, $arg) {
   switch ($path) {
-    case 'admin/settings/language/geoip':
+    case 'admin/config/regional/language/configure/geoip':
       $help = t('<p>This page provides an overview of your site\'s IP detection and language negotiation settings. You may configure which language is chosen when each country is detected from the user\'s IP, using the form below. All detectable languages are listed in the <em>Detected country</em> drop-down list, and all installed languages are listed in t the <em>Language</em> drop-down list. If a country is detected but doesn\'t have an entry in this list, the default language will be used.</p>');
       return $help;
   }
 }
 
 /**
- * Implementation of hook_menu().
+ * Implements hook_menu().
+ *
+ * @return array
  */
 function geoip_language_menu() {
   $items = array();
 
-  $items['admin/settings/language/geoip'] = array(
+  $items['admin/config/regional/language/configure/geoip'] = array(
     'title' => 'GeoIP',
-    'type' => MENU_LOCAL_TASK,
     'weight' => 5,
-    'page callback' => 'geoip_language_settings_overview',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('geoip_language_form'),
     'access arguments' => array('administer languages'),
     'file' => 'geoip_language.admin.inc',
   );
-  $items['admin/settings/language/geoip/delete/%'] = array(
+  $items['admin/config/regional/language/configure/geoip/delete/%'] = array(
     'title' => 'Delete GeoIP mapping',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('geoip_admin_delete_mapping', 5),
+    'page arguments' => array('geoip_admin_delete_mapping', 7),
     'access arguments' => array('administer languages'),
     'type' => MENU_CALLBACK,
     'file' => 'geoip_language.admin.inc',
@@ -48,133 +61,80 @@ function geoip_language_menu() {
 }
 
 /**
- * Implementation of hook_init().
+ * Implements hook_language_negotiation_info().
+ *
+ * @return array
  */
-function geoip_language_init() {
-  // Configured presentation language mode.
-  $mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
-
-  $drush = (function_exists('drush_verify_cli') && drush_verify_cli());
-
-  // Only take action if language negotiation is set to GeoIP and there is more
-  // than 1 enabled language.
-  if (!$drush && ($mode == GEOIP_LANGUAGE_NEGOTIATION_PATH) && ((int)variable_get('language_count', 1) > 1)) {
-    geoip_language_negotiation();
-  }
+function geoip_language_language_negotiation_info() {
+  return array(GEOIP_LANGUAGE_NEGOTIATION => array(
+      'callbacks' => array(
+        'language' => 'language_negotiation_from_geoip',
+        // 'switcher' => 'custom_language_switcher_callback',
+        // 'url_rewrite' => 'custom_language_url_rewrite_callback',
+      ),
+      'file' => drupal_get_path('module', 'geoip_language') . '/geoip_language.module',
+      'weight' => -4,
+      'name' => 'GeoIP',
+      'description' => t('Use the users IP to determine the language'),
+      'config' => 'admin/config/regional/language/configure/geoip',
+      // 'cache' => 0,
+  ),
+  );
 }
 
 /**
- * Determine the appropriate language based on path prefix, with fallbacks for
- * user preferred language and GeoIP mapped language.
+ * Identify language via URL prefix or domain excluding administrative paths.
+ * Try to keep as light weight as possible
+ *
+ * @return string
+ *   Language as ISO 639-1 Code
  */
-function geoip_language_negotiation() {
-  // Get a list of enabled languages.
-  $languages = language_list('enabled');
-  $languages = $languages[1];
-
-  // Get the original q, as it is before path un-aliasing.  This is important
-  // because a path alias which is the same as a language prefix will have been
-  // improperly un-aliased and the language prefix will be lost.
-  $query = array();
-  parse_str($_SERVER['QUERY_STRING'], $query);
-  $q = $query['q'];
-
-  // Mostly copied from language_initialize(). Do a basic path prefix lookup to
-  // determine the language.
-  $args = explode('/', $q);
-  $prefix = array_shift($args);
-  // Search prefix within enabled languages.
-  foreach ($languages as $language) {
-    if (!empty($language->prefix) && $language->prefix == $prefix) {
-      // Set the global language object.
-      $GLOBALS['language'] = $language;
-      // Rebuild $_GET['q'] with the language removed.
-      $_GET['q'] = implode('/', $args);
-      // Re-initialize the path.
-      drupal_init_path();
-      // Make PressFlow happy by only storing the language code if there's an
-      // existing session.
-      if (count($_SESSION)) {
-        $_SESSION['geoip_language'] = $language->language;
-      }
-      return;
-    }
-  }
-
-  // Begin fallbacks. At this point, we know that there is not a valid path
-  // prefix, so we must first determine a language, and then do a redirect to
-  // the current path, in that language.
-
-  global $user;
-  // First check to see if a language was previously determined.
-  if (isset($_SESSION['geoip_language']) && isset($languages[$_SESSION['geoip_language']])) {
-    $language = $languages[$_SESSION['geoip_language']];
-  }
-  // Fallback for user-preferred language.
-  elseif ($user->uid && isset($languages[$user->language])) {
-    $language = $languages[$user->language];
-  }
-  // If all else fails, do a GeoIP lookup and redirect.
-  else {
-    $language = geoip_language_detect_language();
-  }
-
-
-  // Set the global language object.
-  $GLOBALS['language'] = $language;
-
-  global $base_path;
-  // Abort the redirect if bootstrap happened outside of index.php or if the
-  // requested path is inside the files directory
-  if (($_SERVER['SCRIPT_NAME'] != $base_path .'index.php')
-    || (strpos($_GET['q'], file_directory_path()) === 0)
-    || ($_SERVER['REQUEST_METHOD'] == 'POST')) {
-    return;
-  }
-
-  // Now that the language is detected, do an absolute redirect to avoid page
-  // caching in the wrong language.
-  $url = url($_GET['q'], array('language' => $language, 'absolute' => TRUE, 'query' => drupal_query_string_encode($_GET, array('q'))));
-  drupal_goto($url, NULL, NULL, 301);
-  exit();
+function language_negotiation_from_geoip($languages) {
+  // Use the core URL language provider to get a valid language code.
+  include_once DRUPAL_ROOT . '/includes/locale.inc';
+  include_once DRUPAL_ROOT . '/modules/locale/locale.module';
+  include_once dirname(__FILE__) . '/../geoip.module';
+  $langcode = geoip_language_detect_language();
+
+  return $langcode;
 }
 
 /**
- * Implementation of custom_url_rewrite_outbound().
+ * Implements custom_url_rewrite_outbound().
  * language_url_rewrite() doesn't add the path prefix for the default language,
  * so we are doing it here.  This lessens the amount of redirection that
  * would occur because of a missing path prefix.
+ *
+ * @TODO Function disabled - looks like this is not necessary anymore in D7
  */
-if (!function_exists('custom_url_rewrite_outbound')) {
-  function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
-    global $language;
-
-    if (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) == GEOIP_LANGUAGE_NEGOTIATION_PATH
-      && ((int)variable_get('language_count', 1) > 1)) {
-      // Only modify relative (insite) URLs.
-      if (!$options['external']) {
-
-        // Allow links to bypass the language prefixing.  Helpful for simpletest.
-        // Breaking forms as of 2009-06-22
-//        if (isset($options['geoip_language_no_prefix']) && ($options['geoip_language_no_prefix'] === TRUE)) {
-//          return;
+function _geoip_language_url_outbound_alter(&$path, &$options, $original_path) {
+//    global $language;
+//
+//    if (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) == GEOIP_LANGUAGE_NEGOTIATION_PATH
+//      && ((int) variable_get('language_count', 1) > 1)) {
+//      // Only modify relative (insite) URLs.
+//      if (!$options['external']) {
+//
+//        // Allow links to bypass the language prefixing.  Helpful for simpletest.
+//        // Breaking forms as of 2009-06-22
+////        if (isset($options['geoip_language_no_prefix']) && ($options['geoip_language_no_prefix'] === TRUE)) {
+////          return;
+////        }
+//
+//        // Language can be passed as an option, or we go for current language.
+//        if (!isset($options['language'])) {
+//          $options['language'] = $language;
 //        }
-
-        // Language can be passed as an option, or we go for current language.
-        if (!isset($options['language'])) {
-          $options['language'] = $language;
-        }
-
-        if (!empty($options['language']->prefix)) {
-          $options['prefix'] = $options['language']->prefix .'/';
-        }
-      }
-    }
-  }
+//
+//        if (!empty($options['language']->prefix)) {
+//          $options['prefix'] = $options['language']->prefix . '/';
+//        }
+//      }
+//    }
 }
 
 /**
- * Implementation of hook_form_locale_languages_configure_form_alter().
+ * Implements hook_form_locale_languages_configure_form_alter().
  */
 function geoip_language_form_locale_languages_configure_form_alter(&$form, $form_state) {
   $form['language_negotiation']['#options'][GEOIP_LANGUAGE_NEGOTIATION_PATH] = t('Path prefix with GeoIP detection fallback.');
@@ -182,6 +142,8 @@ function geoip_language_form_locale_languages_configure_form_alter(&$form, $form
 
 /**
  * API function to create a new mapping.
+ *
+ * @return array
  */
 function geoip_language_mapping_create($country, $language) {
   $data = array(
@@ -189,23 +151,40 @@ function geoip_language_mapping_create($country, $language) {
     'language' => $language,
   );
   drupal_write_record('geoip_language', $data);
-  geoip_language_mappings(TRUE);
 
   $countries = geoip_country_values();
-  watchdog('geoip_language', 'GeoIP mapping created for %country', array('%country' => $countries[$country]));
+  watchdog(
+    'geoip_language',
+    'GeoIP mapping created for %country',
+    array('%country' => $countries[$country])
+  );
+
+  geoip_language_mappings(TRUE);
 
   return $data;
 }
 
 /**
  * API function to delete a mapping.
+ *
+ * @return boolean
  */
 function geoip_language_mapping_delete($country) {
-  db_query('DELETE FROM {geoip_language} WHERE country="%s"', $country);
-  geoip_language_mappings(TRUE);
+  // On error an Exception is thrown
+  db_delete('geoip_language')
+            ->condition('country', $country)
+            ->execute();
 
   $countries = geoip_country_values();
-  watchdog('geoip_language', 'GeoIP mapping deleted for %country', array('%country' => $countries[$country]));
+  watchdog(
+    'geoip_language',
+    'GeoIP mapping deleted for %country',
+    array('%country' => $countries[$country])
+  );
+
+  geoip_language_mappings(TRUE);
+
+  return TRUE;
 }
 
 /**
@@ -213,15 +192,17 @@ function geoip_language_mapping_delete($country) {
  *
  * TODO: Serializing to a text file is insane. This should go into the cache
  * table instead.
+ *
+ * @return array
+ *  Associative array key=countrycode, value= Language as ISO 639-1 Code
  */
 function geoip_language_mappings($reset = FALSE) {
-  static $mapping = NULL;
+  $mapping = drupal_static(__FUNCTION__, NULL);
 
   if ($reset || !isset($mapping)) {
-    $file = file_directory_path() .'/geoip_language.txt';
-    if (file_exists($file)) {
-      $data = unserialize(file_get_contents($file));
-      $mapping = isset($data['geoip']) ? $data['geoip'] : NULL;
+    $data = cache_get(__METHOD__);
+    if ($data != FALSE) {
+      $mapping = isset($data->data['geoip']) ? $data->data['geoip'] : NULL;
     }
 
     // Build the mapping array and cache it to the filesystem.
@@ -231,14 +212,17 @@ function geoip_language_mappings($reset = FALSE) {
         'geoip' => array(),
         'default' => language_default('prefix'),
       );
-      $result = db_query('SELECT g.*, l.prefix FROM {geoip_language} g INNER JOIN {languages} l on g.language = l.language ORDER BY g.country ASC');
-      while ($row = db_fetch_object($result)) {
+      $result = db_query(
+        'SELECT g.*, l.prefix ' .
+        'FROM {geoip_language} g ' .
+        'INNER JOIN {languages} l on g.language = l.language ' .
+        'ORDER BY g.country ASC'
+      );
+      foreach ($result as $row) {
         $mapping[$row->country] = $row->language;
         $data['geoip'][$row->country] = $row;
       }
-
-      // Add default
-      $file = file_save_data(serialize($data), 'geoip_language.txt', FILE_EXISTS_REPLACE);
+      $data = cache_set(__METHOD__, $data);
     }
   }
 
@@ -247,38 +231,50 @@ function geoip_language_mappings($reset = FALSE) {
 
 /**
  * Return the language object mapped to the current GeoIP detected country.
+ *
+ * @return string
+ *  Language as ISO 639-1 Code
+ *  @link http://de.wikipedia.org/wiki/ISO_639#ISO_639-1  @endlink
  */
 function geoip_language_detect_language($reset = FALSE) {
   static $geoip_language = NULL;
 
   if ($reset || !isset($geoip_language)) {
-    // Get a list of enabled languages.
-    $languages = language_list('enabled');
-    $languages = $languages[1];
     // Get a list of country->language mappings.
     $mappings = geoip_language_mappings();
     // GeoIP detect the current country.
     $country_code = geoip_country_code();
 
-    // Make sure country_code, the mapping for that country_code, and the enabled
-    // language for that mapping, all exist.
-    if ($country_code && $mappings[$country_code] && $languages[$mappings[$country_code]->language]) {
-      $geoip_language = $languages[$mappings[$country_code]->language];
-    }
-    else {
-      $geoip_language = language_default();
+    // Make sure country_code, the mapping for that country_code, and the
+    // enabled language for that mapping, all exist.
+    if ($country_code && isset($mappings[$country_code])) {
+      $geoip_language = $mappings[$country_code]->language;
     }
   }
-
   return $geoip_language;
 }
 
 /**
- * Implementation of hook_flush_caches().
+ * Implements hook_flush_caches().
+ *
+ * @return array
+ *  Return an empty array - we do the flush ourselfes
  */
 function geoip_language_flush_caches() {
   // Reload the geoip cache file.
   geoip_language_mappings(TRUE);
-
   return array();
 }
+
+/**
+ * Implements hook_theme().
+ *
+ * @return array()
+ */
+function geoip_language_theme() {
+  return array(
+    'geoip_language_mapping_overview' => array(
+      'arguments' => array('form' => NULL),
+    ),
+  );
+}
diff --git a/geoip_language/geoip_language.test b/geoip_language/geoip_language.test
index 53d17e1..33d1fc7 100644
--- a/geoip_language/geoip_language.test
+++ b/geoip_language/geoip_language.test
@@ -28,7 +28,7 @@ class geoipLanguageTestCase extends DrupalWebTestCase {
     $this->drupalLogin($this->admin_user);
 
     // Make sure default language has a prefix.
-    $this->drupalPost('admin/settings/language/edit/en', array('prefix' => 'global'), t('Save language'));
+    $this->drupalPost('admin/config/regional/edit/en', array('prefix' => 'global'), t('Save language'));
     // Add and map french/france
     $this->addLanguage('fr');
     geoip_language_mapping_create('FR', 'fr');
@@ -51,13 +51,13 @@ class geoipLanguageTestCase extends DrupalWebTestCase {
    */
   function addLanguage($language_code) {
     // Check to make sure that language has not already been installed.
-    $this->drupalGet('admin/settings/language');
+    $this->drupalGet('admin/config/language');
 
     if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
       // Doesn't have language installed so add it.
       $edit = array();
       $edit['langcode'] = $language_code;
-      $this->drupalPost('admin/settings/language/add', $edit, t('Add language'));
+      $this->drupalPost('admin/config/regional/add', $edit, t('Add language'));
 
       $languages = language_list('language', TRUE); // Make sure not using cached version.
       $this->assertTrue(array_key_exists($language_code, $languages), t('%language language was installed successfully.', array('%language' => $languages[$language_code]->name)));
@@ -81,12 +81,12 @@ class geoipLanguageTestCase extends DrupalWebTestCase {
   function testMappingCrud() {
     $mappings = geoip_language_mappings(TRUE);
     $this->assertFalse(array_key_exists('US', $mappings), t('No mapping for US'));
-    $this->drupalPost('admin/settings/language/geoip', array('country' => 'US', 'language' => 'en'), t('Add mapping'), array('language' => $GLOBALS['language']));
+    $this->drupalPost('admin/config/regional/language/configure/geoip', array('country' => 'US', 'language' => 'en'), t('Add mapping'), array('language' => $GLOBALS['language']));
 
     $mappings = geoip_language_mappings(TRUE);
     $this->assertEqual($mappings['US'], 'en', t('Mapping created for US => en'));
 
-    $this->drupalPost('admin/settings/language/geoip/delete/US', array(), t('Delete'));
+    $this->drupalPost('admin/config/regional/language/configure/geoip/delete/US', array(), t('Delete'));
     $mappings = geoip_language_mappings(TRUE);
     $this->assertFalse(array_key_exists('US', $mappings), t('US mapping deleted.'));
   }
@@ -130,4 +130,4 @@ class geoipLanguageTestCase extends DrupalWebTestCase {
     $this->assertEqual($this->getUrl(), $url, t('Redirect to french path (%url).', array('%url' => $this->getUrl())));
   }
 
-}
\ No newline at end of file
+}
diff --git a/lib/README.txt b/lib/README.txt
index fe84e7c..cf246c1 100644
--- a/lib/README.txt
+++ b/lib/README.txt
@@ -1,4 +1,3 @@
-
 GeoIP API Library
 --------------------
 The geoip module uses MaxMind's GeoIP PHP API to interact with the databases.
diff --git a/lib/geoipcity.inc b/lib/geoipcity.inc
index 08efe52..4e7b397 100644
--- a/lib/geoipcity.inc
+++ b/lib/geoipcity.inc
@@ -67,9 +67,9 @@ class geoipdnsrecord {
 
 function getrecordwithdnsservice($str){
   $record = new geoipdnsrecord;
-  $keyvalue = split(";",$str);
+  $keyvalue = explode(";",$str);
   foreach ($keyvalue as $keyvalue2){
-    list($key,$value) = split("=",$keyvalue2);
+    list($key,$value) = explode("=",$keyvalue2);
     if ($key == "co"){
       $record->country_code = $value;
     }
