diff --git a/imagefield_crop.install b/imagefield_crop.install
new file mode 100644
index 0000000..611a3c8
--- /dev/null
+++ b/imagefield_crop.install
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Install / Uninstall file for Imagefield Crop.
+ *
+ * Heavily inspired from imagecrop - http://drupal.org/project/imagecrop
+ */
+
+/**
+ * Implements hook_schema().
+ * @TODO: We need defaults for all of our items.
+ */
+function imagefield_crop_schema() {
+
+  $schema['imagefield_crop_settings'] = array(
+    'description' => 'Stores imagefield crop settings for files.',
+    'fields' => array(
+      'fid' => array(
+        'type' => 'int', 
+        'not null' => TRUE, 
+        'unsigned' => TRUE
+      ),
+      'isid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE
+      ),
+      'xoffset' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE, 
+        'default' => 0,
+      ),
+      'yoffset' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+      ),
+      'width' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+      ),
+      'height' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'indexes' => array(
+      'fid' => array('fid'),
+      'isid' => array('isid'),
+    ),
+  );
+
+  return $schema;
+
+}
\ No newline at end of file
diff --git a/imagefield_crop.js b/imagefield_crop.js
index fae3f54..5ea3395 100644
--- a/imagefield_crop.js
+++ b/imagefield_crop.js
@@ -6,7 +6,6 @@ Drupal.behaviors.imagefield_crop = {
   attach: function (context, settings) {
     // wait till 'fadeIn' effect ends (defined in filefield_widget.inc)
     setTimeout(attachJcrop, 1000, context);
-    //attachJcrop(context);
 
     function attachJcrop(context) {
       if ($('.cropbox', context).length == 0) {
@@ -17,52 +16,53 @@ Drupal.behaviors.imagefield_crop = {
       $('.cropbox', context).once(function() {
         var self = $(this);
 
-        //alert("found a cropbox" + self.attr('id'));
-
         // get the id attribute for multiple image support
         var self_id = self.attr('id');
         var id = self_id.substring(0, self_id.indexOf('-cropbox'));
         // get the name attribute for imagefield name
         var widget = self.parent().parent();
 
-          if ($(".edit-image-crop-changed", widget).val() == 1) {
-              $('.preview-existing', widget).css({display: 'none'});
-              $('.jcrop-preview', widget).css({display: 'block'});
-          }
+        if ($(".edit-image-crop-changed", widget).val() == 1) {
+          $('.preview-existing', widget).css({display: 'none'});
+          $('.jcrop-preview', widget).css({display: 'block'});
+        }
 
+        //$(this).Jcrop();
         $(this).Jcrop({
           onChange: function(c) {
             $('.preview-existing', widget).css({display: 'none'});
-            var preview = $('.imagefield-crop-preview', widget);
+            //var preview = $('.imagefield-crop-preview', widget);
             // skip newly added blank fields
-            if (undefined == settings.imagefield_crop[id].preview) {
+            /*if (undefined == settings.imagefield_crop[id].preview) {
               return;
-            }
-            var rx = settings.imagefield_crop[id].preview.width / c.w;
-            var ry = settings.imagefield_crop[id].preview.height / c.h;
-            $('.jcrop-preview', preview).css({
+            }*/
+            //var rx = settings.imagefield_crop[id].preview.width / c.w;
+            //var ry = settings.imagefield_crop[id].preview.height / c.h;
+            /*$('.jcrop-preview', preview).css({
               width: Math.round(rx * settings.imagefield_crop[id].preview.orig_width) + 'px',
               height: Math.round(ry * settings.imagefield_crop[id].preview.orig_height) + 'px',
               marginLeft: '-' + Math.round(rx * c.x) + 'px',
               marginTop: '-' + Math.round(ry * c.y) + 'px',
               display: 'block'
-            });
+            });*/
           },
           onSelect: function(c) {
-            $('.preview-existing', widget).css({display: 'none'});
+            //$('.preview-existing', widget).css({display: 'none'});
             $(".edit-image-crop-x", widget).val(c.x);
             $(".edit-image-crop-y", widget).val(c.y);
             if (c.w) $(".edit-image-crop-width", widget).val(c.w);
             if (c.h) $(".edit-image-crop-height", widget).val(c.h);
             $(".edit-image-crop-changed", widget).val(1);
           },
-          aspectRatio: settings.imagefield_crop[id].box.ratio,
-          boxWidth: settings.imagefield_crop[id].box.box_width,
-          boxHeight: settings.imagefield_crop[id].box.box_height,
-          minSize: [Drupal.settings.imagefield_crop[id].minimum.width, Drupal.settings.imagefield_crop[id].minimum.height], 
+          aspectRatio: $('.edit-image-crop-ratio', widget).val(),
+          boxWidth: 400,
+          boxHeight: 400,
+          //boxWidth: settings.imagefield_crop[id][image_style].box.box_width,
+          //boxHeight: settings.imagefield_crop[id][image_style].box.box_height,
+          //minSize: [Drupal.settings.imagefield_crop[id][image_style].minimum.width, Drupal.settings.imagefield_crop[id][image_style].minimum.height], 
           /*
            * Setting the select here calls onChange event, and we lose the original image visibility
-          */
+           */
           setSelect: [
             parseInt($(".edit-image-crop-x", widget).val()),
             parseInt($(".edit-image-crop-y", widget).val()),
diff --git a/imagefield_crop.module b/imagefield_crop.module
index 91bff5a..a13c9f8 100644
--- a/imagefield_crop.module
+++ b/imagefield_crop.module
@@ -1,10 +1,117 @@
 <?php
 
 /**
+ * Implements hook_image_effect_info().
+ */
+function imagefield_crop_image_effect_info() {
+  $effects = array();
+  $effects['imagefield_crop_javascript'] = array(
+    'label' => t('User-selected crop'),
+    'help' => t('Users define crops on a per-image basis.'),
+    'effect callback' => 'imagefield_crop_effect',
+    'form callback' => 'imagefield_crop_effect_form',
+    'summary theme' => 'imagefield_crop_effect_summary',
+  );
+
+  return $effects;
+}
+
+/**
+ * Image effect callback: Crop the image based on the javascript selected crop.
+ *
+ * @param $image An image object returned by image_load().
+ * @param $data An array of settings from the user for cropping the image.
+ * @return TRUE on success. FALSE on failure to crop the image.
+ *
+ */
+function imagefield_crop_effect(&$image, $data) {
+  $success = TRUE;
+  
+  // @TODO: When previewing, there isn't an image style with the data. This is ugly. Thoughts?
+  $image_style = (!empty($data['image_style'])) ? $data['image_style'] : arg(5);
+  
+  $file_info = db_query('SELECT * FROM {file_managed} WHERE uri = :uri', array(':uri' => $image->source))->fetchObject();
+  $isid = db_query('SELECT isid FROM {image_styles} WHERE name = :name', array(':name' => $image_style))->fetchField();
+  
+  $image_data = NULL;
+  
+  if (!empty($isid) && !empty($file_info)) {
+    $image_data = db_query('SELECT * FROM {imagefield_crop_settings} WHERE fid = :fid && isid = :isid', array(':fid' => $file_info->fid, ':isid' => $isid))->fetchObject();
+  }
+  
+  if (!empty($image_data)) {
+    // Crop defined in db.
+    $success = image_crop($image, $image_data->xoffset, $image_data->yoffset, $image_data->width, $image_data->height);
+  }
+  
+  // now, scale to defined limit. If there wasn't a crop, this just scales the image.
+  if ($success) {
+    $success = image_scale($image, $data['width'], $data['height']);
+  }
+
+  return $success;
+}
+
+/**
+ * Settings form for configuring a javascript imagecrop effect.
+ */
+function imagefield_crop_effect_form($data) {
+  $form = image_scale_form($data);
+  
+  $form['description'] = array(
+    '#type' => 'item',
+    '#markup' => '@TODO: Explain what\'s going on. The width/height defines the final size of the image.',
+    '#title' => t('Instructions'),
+    '#weight' => -10,
+  );
+  
+  $form['image_style'] = array(
+    '#type' => 'value',
+    '#value' => arg(5), // Image style from uri.
+  );
+
+  return $form;
+}
+
+/**
+ * Implements hook_image_style_flush().
+ */
+ 
+function imagefield_crop_image_style_flush($style) {
+  db_delete('imagefield_crop_settings')
+    ->condition('isid', $style['isid'])
+    ->execute();
+}
+
+/**
+ * Reset the cropped images when the reset checkbox is enabled.
+ */
+function imagecrop_javascript_effect_submit($form, &$form_state) {
+
+  if ($form_state['values']['reset-crops'] === 1) {
+    db_update('imagefield_crop_settings')
+      ->fields(array('width' => $form_state['values']['data']['width'], 'height' => $form_state['values']['data']['height']))
+      ->condition('width', $form_state['values']['old-width'])
+      ->condition('height', $form_state['values']['old-height'])
+      ->condition('isid', $form_state['image_effect']['isid'])
+      ->execute();
+  }
+
+}
+
+/**
+ * Summary callback for image effect.
+ */
+
+function imagecrop_effect_summary(&$data) {
+  return "@TODO: Description";
+}
+
+/**
  * Implements hook_field_widget_info().
  */
+
 function imagefield_crop_field_widget_info() {
-  //dpm(__FUNCTION__);
   return array(
     'imagefield_crop_widget' => array(
       'label' => t('Image with cropping'),
@@ -29,6 +136,7 @@ function imagefield_crop_field_widget_info() {
 /**
  * Implements hook_field_widget_settings_form().
  */
+
 function imagefield_crop_field_widget_settings_form($field, $instance) {
   //dpm(__FUNCTION__);
   $widget = $instance['widget'];
@@ -176,7 +284,129 @@ function imagefield_crop_field_widget_form(&$form, &$form_state, $field, $instan
 }
 
 /**
+ * Implements hook_form_field_ui_field_edit_form_alter().
+ * Add the imagecrop setting to an imagefield.
+ */
+function imagefield_crop_form_field_ui_field_edit_form_alter(&$form, $form_state) {
+  if ($form['#field']['type'] == 'image') {
+    $styles = imagefield_crop_get_imagecrop_styles();
+    if (count($styles) > 0) {
+      $form['instance']['settings']['imagecrop'] = array(
+        '#type' => 'checkboxes',
+        '#options' => $styles,
+        '#title' => t('Available imagecrop styles'),
+        '#description' => t('Select which imagecrop styles should be available for this field'),
+        '#weight' => 12,
+        '#default_value' => isset($form_state['build_info']['args'][0]['settings']['imagecrop']) ? $form_state['build_info']['args'][0]['settings']['imagecrop'] : array(),
+      );
+    }
+  }
+}
+
+/**
+ * Return a list of presets.
+ *
+ * @param $enabled_styles array of styles that are enabled for a field
+ * @return $presets array with presetid to load and list of all other possible presets.
+ */
+function imagefield_crop_get_imagecrop_styles($enabled_styles = array()) {
+
+  $apply_filter = (count($enabled_styles) > 0);
+
+  $all_styles = image_styles();
+  $styles = array();
+  foreach ($all_styles as $key => $style) {
+    foreach ($style['effects'] as $effect) {
+      if ($effect['name'] == 'imagefield_crop_javascript') {
+
+        // Skip if current style is not enabled.
+        if ($apply_filter && !in_array($style['isid'], $enabled_styles)) {
+          continue;
+        }
+        $styles[$style['isid']] = $style['name'];
+
+      }
+    }
+  }
+
+  return $styles;
+
+}
+
+/**
+ * Implements hook_element_info_alter().
+ */
+function imagefield_crop_element_info_alter(&$type) {
+  $type['managed_file']['#process'][] = 'process_imagefield_crop_form_element';
+  $type['managed_file']['#element_validate'][] = 'imagefield_crop_widget_submit'; // See note with function
+}
+
+/**
+ * Process function for imagecrop-enabled fields.
+ */
+function process_imagefield_crop_form_element($element, &$form_state) { 
+  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
+  
+  // @TODO: Not sure if this is the best check for availaibility.
+  if (count($instance['settings']['imagecrop'] > 0)) {  
+    $item = $element['#value'];
+    $item['fid'] = $element['fid']['#value'];
+    
+    //$element['#theme'] = 'imagefield_crop_widget';
+    $element['#description'] = t('Click on the image and drag to mark how the image will be cropped');
+    
+    $image_styles = array();
+    foreach ($instance['settings']['imagecrop'] as $isid) {
+      $style = image_style_load(NULL, $isid);
+      $image_styles[$isid] = $style['name'];
+    }
+    
+    $path = drupal_get_path('module', 'imagefield_crop');
+    $element['#attached']['js'][] = "$path/Jcrop/js/jquery.Jcrop.js";
+    // We must define Drupal.behaviors for ahah to work, even if there is no file
+    $element['#attached']['js'][] = "$path/imagefield_crop.js";
+    $element['#attached']['css'][] = "$path/Jcrop/css/jquery.Jcrop.css";
+    
+    if (!empty($element['#file'])) {
+      $file_to_crop = _imagefield_crop_file_to_crop($element['#file']->fid);
+      
+      // @TODO: for each image style, create a field set with the info below.
+      
+      $element['crops'] = array(
+        '#type' => 'container',
+        '#attributes' => array(),
+      );
+      
+      $settings = array(
+        $element['#id'] => array(),
+      );
+      
+      foreach ($image_styles as $key => $name) {
+        $element['crops'][$key] = array(
+          '#type' => 'fieldset',
+          '#title' => $name,
+        );
+        
+        $element['crops'][$key]['cropbox'] = array(
+          '#markup' => theme('image', array(
+            'path' => $file_to_crop->uri,
+            'attributes' => array(
+              'class' => 'cropbox',
+              'id' => $element['#id'] . '-cropbox'))),
+        );
+        
+        $element['crops'][$key]['cropinfo'] = _imagefield_crop_add_cropinfo_fields($element['#file']->fid, $key);
+      }
+    }
+  }
+  
+  return $element;
+}
+
+/**
  * An element #process callback for the imagefield_crop field type.
+ *
+ * @TODO: Depreciate. Using the function above instead.
  */
 function imagefield_crop_widget_process($element, &$form_state, $form) {
   //dpm(__FUNCTION__);
@@ -217,7 +447,7 @@ function imagefield_crop_widget_process($element, &$form_state, $form) {
             'class' => 'cropbox',
             'id' => $element['#id'] . '-cropbox'))),
     );
-    $element['cropinfo'] = _imagefield_add_cropinfo_fields($element['#file']->fid);
+    $element['cropinfo'] = _imagefield_crop_add_cropinfo_fields($element['#file']->fid);
     list($res_w, $res_h) = explode('x', $widget_settings['resolution']);
     list($crop_w, $crop_h) = explode('x', $widget_settings['croparea']);
     $settings = array(
@@ -247,20 +477,93 @@ function imagefield_crop_widget_process($element, &$form_state, $form) {
   return $element;
 }
 
-function _imagefield_add_cropinfo_fields($fid = NULL) {
+/**
+ * Validate callback for this element.
+ *
+ * Technical note: This is done through a validation hook instead of a submit hook. Submit hooks aren't called on an element level
+ *   for managed_file elements (nor most elements), so this is the closest we get. As such, we need to take into account the possibility
+ *   that a validation call doesn't necessarily mean that the field is actually being saved.
+ */
+ 
+function imagefield_crop_widget_submit($form, $form_state) {
+  // @TODO: Push variables into db.  
+  $field_name = $form['#field_name'];
+  $values = $form_state['values'][$field_name]['und'];
+  
+  foreach ($values as $file) {
+    $file = $file;
+    foreach ($file['crops'] as $isid => $crop) {
+      // Clear out potential old values first.
+      db_delete('imagefield_crop_settings')
+        ->condition('fid', $file['fid'])
+        ->condition('isid', $isid)
+        ->execute();
+
+      db_insert('imagefield_crop_settings')
+        ->fields(array(
+          'fid' => $file['fid'],
+          'isid' => $isid,
+          'xoffset' => (!empty($crop['cropinfo']['x'])) ? $crop['cropinfo']['x'] : 0,
+          'yoffset' => (!empty($crop['cropinfo']['y'])) ? $crop['cropinfo']['y'] : 0,
+          'width' => (!empty($crop['cropinfo']['width'])) ? $crop['cropinfo']['width'] : 50,
+          'height' => (!empty($crop['cropinfo']['height'])) ? $crop['cropinfo']['height'] : 50,
+        ))
+        ->execute();
+        
+      // be sure to delete the created image style for regeneration.
+      $style_info = image_style_load(NULL, $isid);
+      $file_object = file_load($file['fid']);
+      $thumbnail_uri = image_style_path($style_info['name'], $file_object->uri);
+      if (file_exists($thumbnail_uri)) {
+        unlink($thumbnail_uri);
+      }
+    }
+  }
+    
+  // tmp, need to throw error.
+  //db_query('SELECT test FROM {node}');
+}
+
+/**
+ * Loads defaults for crop.
+ *
+ * @fid - File ID.
+ * @isid - Image Style ID.
+ */
+
+function _imagefield_crop_add_cropinfo_fields($fid = NULL, $isid = NULL) {
+  $style = image_style_load(NULL, $isid);
+  $effect = array();
+  foreach ($style['effects'] as $effect) {
+    if ($effect['label'] == 'User-selected crop') {
+      $effect = image_effect_load($effect['ieid'], $style['name']);
+      break;
+    }
+  }
   $defaults = array(
     'x'       => 0,
     'y'       => 0,
     'width'   => 50,
     'height'  => 50,
     'changed' => 0,
+    'ratio' => '',
   );
-  if($fid) {
-  	$crop_info = variable_get('imagefield_crop_info', array());
-  	if(isset($crop_info[$fid]) && !empty($crop_info[$fid])) {
-  		$defaults = array_merge($defaults,$crop_info[$fid]);
+  if(!empty($fid)) {
+  	$crop_info = db_query('SELECT * FROM {imagefield_crop_settings} WHERE fid = :fid && isid = :isid', array(':fid' => $fid, ':isid' => $isid))->fetchAssoc();
+  	if(isset($crop_info)) {
+      $from_db = array(
+        'x' => $crop_info['xoffset'],
+        'y' => $crop_info['yoffset'],
+        'width' => $crop_info['width'],
+        'height' => $crop_info['height'],
+      );
+  		$defaults = array_merge($defaults,$from_db);
   	}
   }
+  
+  if (!empty($effect['data']['width']) && !empty($effect['data']['height'])) {
+    $defaults['ratio'] = round($effect['data']['width'] / $effect['data']['height'], 3);
+  }
 
   foreach ($defaults as $name => $default) {
     $element[$name] = array(
@@ -270,6 +573,7 @@ function _imagefield_add_cropinfo_fields($fid = NULL) {
       '#default_value' => $default,
     );
   }
+  
   return $element;
 }
 
@@ -319,6 +623,7 @@ function imagefield_crop_widget_preview_process($element, &$form_state, $form) {
  *
  * Registered by imagefield_crop_field_widget_form()
  */
+
 function imagefield_crop_widget_value(&$element, &$input, $form_state) {
   // set $input['fid'] and that will be the value of the element
   if (!empty($input['fid']) && $input['cropinfo']['changed']) {
@@ -372,63 +677,19 @@ function imagefield_crop_widget_delete($form, &$form_state) {
 	}
 }
 
-/*********************/
-/* Theming functions */
-/*********************/
-
 /**
- * Implements hook_theme().
+ * Internal functions
  */
-function imagefield_crop_theme() {
-  return array(
-    'imagefield_crop_widget' => array(
-      'render element' => 'element'),
-    'imagefield_crop_preview' => array(
-      'render element' => 'element',
-    ),
-  );
-}
-
-function theme_imagefield_crop_widget($variables) {
-  //dpm(__FUNCTION__);
-  $element = $variables['element'];
-  $output = '';
-  $output .= '<div class="imagefield-crop-widget form-managed-file clearfix">';
-
-  //$output .= '<pre>' . print_r($element['#attached'],1) . '</pre>';
-  if (isset($element['preview'])) {
-    $output .= '<div class="imagefield-crop-preview">';
-    $output .= drupal_render($element['preview']);
-    $output .= '</div>';
-  }
-  if (isset($element['cropbox'])) {
-    $output .= '<div class="imagefield-crop-cropbox">';
-    $output .= drupal_render($element['cropbox']);
-    $output .= '</div>';
-  }
-  $output .= drupal_render_children($element);
-  return $output;
-}
-
-function theme_imagefield_crop_preview($variables) {
-  //dpm(__FUNCTION__);
-  $info = $variables['element']['#imagefield_crop'];
-  $output = '<div class="jcrop-preview-wrapper" style="width:'. $info['#width'] .'px;height:'. $info['#height'] .'px;overflow:hidden;">';
-  $output .= $variables['element']['#markup'];
-  $output .= theme('image', array('path' => $info['#path'], 'alt' => 'jcrop-preview', 'attributes' => array('class' => 'jcrop-preview', 'style' => 'display:none')));
-  $output .= '</div>';
-  return $output;
-}
-
-/*********************/
-/* Internal functions */
-/*********************/
 
 /**
  * Crop the image and resize it
+ *
+ * @src = path to image.
+ * @crop = Array of crop options, keys 'x', 'y', 'width', 'height'
+ * @scale = Array of scale options, keys 'width', 'height'
+ * @dst = Destination path.
  */
 function _imagefield_crop_resize($src, $crop = NULL, $scale = NULL, $dst = NULL) {
-  //dpm(__FUNCTION__);
   $image = image_load($src);
   if ($image) {
     $result = TRUE;
