<?php // (C) Copyright Bobbing Wide 2012,2013
/**
 * Logic to create metaboxes for each of the custom fields defined for a particular post type
 *
 * Note: These functions are prefixed bw_effort for historical reasons 
 * 
 */

/** 
 * Function to invoke when bw_metadata.inc is loaded
 */
function bw_metadata_loaded() {
  add_action( 'add_meta_boxes', 'bw_effort_meta_boxes' );
  /* Do something with the data entered */
  add_action( 'save_post', 'bw_effort_save_postdata', 10, 2 );
}

/**
 * Create "Fields" meta box for each field associated with each object type in the mapping
 */
function bw_effort_meta_boxes() {
  oik_require( 'bobbforms.inc' );
  global $bw_mapping;
  bw_trace2( $bw_mapping );
  if ( is_array( $bw_mapping ) && count( $bw_mapping['field'] ) ) {
  
    foreach ( $bw_mapping['field'] as $object_type => $fields ) {
      // bw_trace( "object_type", __FUNCTION__, __LINE__, __FILE__, $object_type );
      // bw_trace2( $fields );
      add_meta_box( 'bw_effort', __( "Fields", "oik"), 'bw_effort_box', $object_type, 'normal' , 'high' , $fields );
    }
  }  
}

/*
 * Return a default value from $args if $value is not set
 *
 * @param string $value the current value
 * @param array $args an array containing the default value
 * @returns string $value
 */
function bw_default_value( $value, $args ) {
  if ( !$value ) {
    $value = bw_array_get( $args, '#default', NULL );
  }
  return( $value );
}

/**
 * bw_form_field_ - default formatting for a field - as a textfield
 *
 * e.g. textfield( '_bw_header_image', 80, "Custom header image", $value );
 */
function bw_form_field_( $name, $type, $title, $value, $args ) {
  $length = bw_array_get( $args, '#length', 40 );
  $value = bw_default_value( $value, $args );
  $class = bw_array_get( $args, "#class", null );
  $extras = bw_array_get( $args, "#extras", null );
  bw_textfield( $name, $length, $title, $value, $class, $extras );
} 

/**
 * bw_form_field_email - formatting for an email entry field
 */
function bw_form_field_email( $name, $type, $title, $value, $args ) {
  $length = bw_array_get( $args, '#length', 40 );
  $value = bw_default_value( $value, $args );
  $class = bw_array_get( $args, "#class", null );
  $extras = bw_array_get( $args, "#extras", null );
  bw_emailfield( $name, $length, $title, $value, $class, $extras );
}

/**
 * bw_form_field_select - formatting for a field as a select list
 * The options come from $args[#options] 
 */
function bw_form_field_select( $name, $type, $title, $value, $args ) {
  bw_select( $name, $title, $value, $args );
}

/** 
 * Build a simple ID, title array from an array of $post objects
 * @param array $post - array of post objects
 * @return array - associative array of post ID to post_title
 */
function bw_post_array( $posts ) {
  $options = array();
  foreach ($posts as $post ) {
    $options[$post->ID] = $post->post_title; 
  }
  return bw_trace2( $options );
}

/** 
 * Build a simple ID, title array from an array of $term objects
 * @param array $term - array of term objects
 * @return array - associative array of term_id to name
 */
function bw_term_array( $terms ) {
  $options = array();
  if ( count( $terms ) ) {
    foreach ($terms as $term ) {
      $options[$term->term_id] = $term->name; 
    }
  }
  return bw_trace2( $options );
}

/**
 * Load an array of node references
 *
 * @param string/array $args - array of args containing the #type of the node to load
 * Note: #type may also be an array of post_types
 * @returns array $options - array of nodes keyed by ID with value of title
 *
 * Note: You can simply pass this as a string if you so wish 
 * 
 * **?** This is probably an inefficient use of get_posts, especially for very large lists
 * **?** Could we not just pass $args to bw_get_posts to allow the returned list to be fine tuned
 * 
 * 
 */
function bw_load_noderef( $args ) {
  oik_require( "includes/bw_posts.inc" );
  $post_types = array();
  $post_type = bw_array_get( $args, '#type', $args );
  if ( is_array( $post_type ) ) { 
    $post_types = $post_type;
  } else {
    $post_types[] = $post_type;
  }   
    
  $options = array();
  foreach ( $post_types as $post_type ) {    
    if ( $post_type !== "attachment" ) {
      $args['post_parent'] = 0; 
    } else {
      unset( $args['post_parent'] );
    }
    $args['post_type'] = $post_type;
    $posts = bw_get_posts( $args );
    $options += bw_post_array( $posts );
  }
  return( $options );
}

/**
 * bw_form_field_noderef - formatting for a field as a select list of a list of nodes of a particular type
 * The options come from $args[#type] 
 */
function bw_form_field_noderef( $name, $type, $title, $value, $args ) {
  $options = bw_load_noderef( $args );
  //$optional = bw_array_get( $args, "#optional", false );
  //if ( $optional ) {
  //  $options = array( "None" ) + $options;
  //}
  $args['#options'] =  $options;
  //$multiple = bw_array_get( $args, "#multiple", false );
  //if ( $multiple ) { 
  //  bw_multiple_select( $name, $title, $value, array( '#options' => $options ));
  //} else {
    bw_select( $name, $title, $value, $args );
  //}
}
   
/**
 * Enqueue the debug script if needed otherwise enqueue the minified (packed) one
 */
if ( !function_exists( "bw_datepicker_enqueue_script" ) ) {
function bw_datepicker_enqueue_script( ) {
  if ( defined('SCRIPT_DEBUG' ) && SCRIPT_DEBUG == true) {
    wp_enqueue_script( 'jquery-ui-datepicker' );
  } else {
    wp_enqueue_script( 'jquery-ui-datepicker' );
  } 
}
} 

/** 
 * bw_form_field_date - format a date field
 *
 * **?** oik v2.0 was delivered with jquery-ui-1.9.2.custom.css but originally expected jquery.ui.theme.css. How do we manage this in the future? 2013/06/26
 *
 */
if ( !function_exists( "bw_form_field_date" ) ) { 
function bw_form_field_date( $name, $type, $title, $value, $args ) {
  $args['#length'] = bw_array_get( $args, '#length', 10 );
  wp_enqueue_style( "jquery-ui-datepicker-css", plugin_dir_url( __FILE__). "css/jquery.ui.datepicker.css" ); 
  //wp_enqueue_style( "jquery-ui-theme-css", plugin_dir_url( __FILE__). "css/jquery.ui.theme.css" );
  wp_enqueue_style( "jquery-ui-theme-css", oik_url( "css/jquery-ui-1.9.2.custom.css" ) );
   
  bw_datepicker_enqueue_script();
  bw_jquery( "#${name}", "datepicker", bw_jkv( "dateFormat : 'yy-mm-dd', changeMonth: true, changeYear: true" ) );
  if ( $value ) {
    $value = bw_format_date( $value );
  }
  bw_form_field_( $name, $type, $title, $value, $args ); 
}
}

/** 
 * Format a numeric field metabox
 *
 */
function bw_form_field_numeric( $name, $type, $title, $value, $args ) {
  $args['#length'] = bw_array_get( $args, '#length', 10 );
  bw_form_field_( $name, $type, $title, $value, $args ); 
}
 
/* 
 * Format a checkbox metabox
 */
function bw_form_field_checkbox( $name, $type, $title, $value, $args ) {
  bw_checkbox( $name, $title, $value );
}

/**
 * Format a textarea metabox
 */
function bw_form_field_textarea( $name, $type, $title, $value, $args ) {
  $len = bw_array_get( $args, "#length", 80 );
  bw_textarea( $name, $len, $title, $value, 10 ); 
}

/**
 * Request plugins to load their field forming functions
 *
 * @uses action "oik_pre_form_field" 
 * Any plugin that provides a field forming function should respond to the "oik_pre_form_field" action to dynamically load the hook that 
 * will be called to form the field. 
 * @See bw_form_function() for hook name suggestions.
 * 
 */
function bw_pre_form_field() {
  static $bw_pre_form_field = 0;
  if ( 0 === $bw_pre_form_field ) {

      /**
       * Request plugins to load field forming functions
       *
       * Any plugin that provides a field forming function should respond to this action by loading the hooks that may be called to form fields.
       */
      do_action( "oik_pre_form_field" );
  }
  $bw_pre_form_field++;
}

/** 
 * Return the function name to be used to 'form' the field
 * 
 * 
 * We append to the $prefix function name to find the most precise name that exists:
 * 
 * $prefix            - default function if the field type is not known
 * $prefix$field_type - e.g. bw_form_field_text or bw_form_field_url
 * $prefix$field_name - e.g. bw_form_field__task_ref
 *
 * @param string $prefix - the prefix for the function name
 * @param string $field_type - type of the field to form
 * @param string $field_name - name of the field to form
 
 * @returns string $funcname - the name of the function to invoke
 * 
 */
function bw_form_function( $prefix="bw_form_field_", $field_type= 'text', $field_name = NULL ) {
  bw_pre_form_field();
  $funcname = $prefix;
  
  $testname = $funcname . $field_type;
  if ( function_exists( $testname ) ) 
    $funcname = $testname;
    
  $testname = $prefix . $field_name; 
  if ( function_exists( $testname ))
    $funcname = $testname;
    
  return bw_trace2( $funcname );
} 

/**
 * Append any #hint to the field_title 
 * 
 * If there is a #hint in the $args then append it to the $field_title within a span with class "bw_hint" 
 * 
 * @param string $field_title - the title of the field
 * @param array $args - array of args, possibly containing a key of '#hint' 
 * @return string $field_title - the updated field title. Note: A single non-blank space character is prepended to the hint text.
 */
function _bw_form_field_title( $field_title, $args ) {
  $hint = bw_array_get( $args, "#hint", null ); 
  if ( $hint ) {
    $sphint = "&nbsp;";
    $sphint .= retstag( "span", "bw_hint" );
    $sphint .= bw_tt( $hint );
    $sphint .= retetag( "span" ); 
    $field_title .= $sphint;
  }  
  return( $field_title );
} 

/**
 * Localize/customize the field title
 * 
 * Allow localization/customization of the field title.
 * Applies the "oik_form_field_title_${field_name}" filter(s) 
 * 
 * If the result is unchanged then return the l10n version, with "oik" as the text-domain
 * 
 * @TODO Or use the value specified in the $args
 * 
 */
function bw_l10n_field_title( $field_name, $field_title, $field_type, $field_value, $args=null ) {
  bw_trace2();
  $stitle = $field_title; 
  $field_title = apply_filters( "oik_form_field_title_${field_name}", $field_title, $field_type );
  if ( $field_title == $stitle ) {
    $field_title = translate( $field_title, "oik" ); // Use translate so that makepot.php/makeoik.php doesn't find this call
  }
  //  $args = apply_filters( "
  $field_title = _bw_form_field_title( $field_title, $args ); 
  return( $field_title );
}

/** 
 * Display a field in a form for the user to enter/choose a value
 * 
 * @param string $field_name - eg. post_title or 
 * @param string $field_type - eg. text, checkbox
 * @param string $field_title - e.g. "Title" 
 * @param string $field_value - current value to display
 * @param array $args - any additional arguments for the field formatter
 */
function bw_form_field( $field_name, $field_type, $field_title, $field_value, $args=NULL ) {
  $field_title = bw_l10n_field_title( $field_name, $field_title, $field_type, $field_value, $args );
  $funcname = bw_form_function( "bw_form_field_", $field_type, $field_name );
  $funcname( $field_name, $field_type, $field_title, $field_value, $args );
}

/**
 * Create fields in the meta box to accept data for the fields
 */
function bw_effort_box( $post, $args ) {
  //bw_bang();
  global $bw_fields; 
  $fields = $args['args'];
  //bw_trace2( $fields );
  stag( 'table', "form-table" );
  foreach ( $fields as $field ) {
    $data = $bw_fields[$field];
    //bw_trace2( $field );
    bw_trace2( $data );
    $multiple = bw_array_get( $data['#args'], "#multiple", false );
    $value = get_post_meta( $post->ID, $field, !$multiple );
    bw_form_field( $field, $data['#field_type'], $data['#title'], $value, $data['#args'] );
  }
  etag( "table" );
  echo( bw_ret());
}

if ( !function_exists( "bw_authorized" ) ) {
  function bw_authorized() {
    $authorized = TRUE;
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
        $authorized = FALSE;
        
    // if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename( __FILE__ ) ) )
    return $authorized;
  }
}

/**
 * Save the custom fields for this post when called for the 'save_post' action
 * 
 * @param integer $post_id The ID of this post
 * @param object $post the post object
 *
 * In order to receive the $post object we need to indicate to add_action that for 'save_post' 
 * we allow two parameters to be passed.
 * From the $post we can determine the $post_type of the object being saved
 * and therefore determine the custom fields from the $bw_mapping global
 * for each field defined for the post type we obtain the value from the $_POST and
 * update the post meta data. 
 */
function bw_effort_save_postdata( $post_id, $post ) {
  if ( bw_authorized() ) {
    $post_type = $post->post_type; 
    
    //bw_trace2( $_POST, "_POST" );
    //bw_trace( $post_type, __FUNCTION__, __LINE__, __FILE__, "post->post_type" );
    /**
     * Save the custom fields for this post
     * @param integer $post_id The ID of this post
     * @param object $post the post object
     */
    do_action( "save_post_${post_type}", $post_id, $post );
  
    global $bw_mapping; 
    bw_trace( $bw_mapping, __FUNCTION__, __LINE__, __FILE__, "bw_mapping" );
    if ( isset(  $bw_mapping['field'][$post_type] )) {
      foreach ( $bw_mapping['field'][$post_type] as $field ) {
        bw_effort_update_field( $post_id, $field );
      }
    }
  } else {
  }   
}

/**
 * Update post_meta for fields with multiple values
 * 
 * Delete any existing meta data values then add the new ones, if any
 *  
 * @param ID $post_id
 * @param string $field - the field name - often preceded with an '_'
 * @param array $mydata - the set of new values 
 */
function bw_update_post_meta( $post_id, $field, $mydata ) {
  delete_post_meta( $post_id, $field );
  if ( count( $mydata ) ) { 
    foreach ( $mydata as $key => $value ) {
      add_post_meta( $post_id, $field, $value, false ); 
    }
  }
}

/**
 * Update the value/values for a field 
 * 
 * What happens if the field is blank **?** 
 * 
 * 
 * 
 */
function bw_effort_update_field( $post_id, $field ) {
  global $bw_mapping;
  global $bw_fields;
  bw_trace2( $bw_fields, "bw_fields" ); 
  $mydata = bw_array_get( $_POST, $field, NULL ) ;
  bw_trace( $mydata, __FUNCTION__, __LINE__, __FILE__, "mydata" );
  if ( $mydata != null ) {
    if ( is_array( $mydata ) ) {
      bw_update_post_meta( $post_id, $field, $mydata );
    } else {
      update_post_meta( $post_id, $field, $mydata );
    }
  } else {
    //
  } 
}

/* 

    [_oik_api_calls] => Array
        (
            [#field_type] => noderef
            [#title] => Uses APIs
            [#args] => Array
                (
                    [#type] => oik_api
                    [#multiple] => 1
                )

        )
*/        

bw_metadata_loaded();
