/**
  * validates if the arguments are valid according to the spec
  * 
  * @param ArgumentsSpec $arguments_spec The arguments specification
  * @param array         $parsed_args    data parsed by the ArgumentsParser
  *
  * @return bool true if the arguments are valid according to the spec
  */
 protected function validate(ArgumentsSpec $arguments_spec, $parsed_args)
 {
     $is_valid = true;
     // check for missing required items or argument values
     foreach ($arguments_spec as $option_spec) {
         $value_specified = (isset($option_spec['short']) and strlen($option_spec['short']) and isset($parsed_args['options'][$option_spec['short']]) and strlen($parsed_args['options'][$option_spec['short']]) or isset($option_spec['long']) and strlen($option_spec['long']) and isset($parsed_args['options'][$option_spec['long']]) and strlen($parsed_args['options'][$option_spec['long']]));
         if ($option_spec['required']) {
             if (!$value_specified) {
                 // required, but not found
                 $is_valid = false;
                 $this->errors[] = "Required value for argument " . $this->longOptionName($option_spec) . " not found.";
             }
         } else {
             if (strlen($option_spec['value_name'])) {
                 if (!$value_specified) {
                     $switch_was_sepcified = (isset($parsed_args['options'][$option_spec['short']]) and isset($parsed_args['options'][$option_spec['short']]) or isset($parsed_args['options'][$option_spec['long']]) and isset($parsed_args['options'][$option_spec['long']]));
                     if ($switch_was_sepcified) {
                         // not required, but a value name is specified and none was given
                         $is_valid = false;
                         $this->errors[] = "No value was specified for argument " . $this->longOptionName($option_spec) . ".";
                     }
                 }
             }
         }
     }
     // find extra argument values that are not defined
     foreach ($parsed_args['options'] as $option_name => $value) {
         $resolved_option_name = $arguments_spec->normalizeOptionName($option_name);
         if ($resolved_option_name === null) {
             $is_valid = false;
             $this->errors[] = "Unknown option " . $option_name . ".";
         }
     }
     // data
     $usage_data = $arguments_spec->getUsage();
     // find required arguments
     foreach ($usage_data['named_args_spec'] as $offset => $named_arg_spec) {
         if ($named_arg_spec['required'] and !isset($parsed_args['numbered_data'][$offset])) {
             $is_valid = false;
             $this->errors[] = "No value for <" . $named_arg_spec['name'] . "> was provided.";
         }
     }
     // find extra arguments
     $expected_values_count = count($usage_data['named_args_spec']);
     if (($data_count = count($parsed_args['numbered_data'])) > $expected_values_count) {
         $extra_count = $data_count - $expected_values_count;
         $is_valid = false;
         $this->errors[] = "Found {$extra_count} unexpected value" . ($extra_count == 1 ? '' : 's') . ".";
     }
     return $is_valid;
 }
 /**
  * builds argument values by long option name
  * 
  * @param ArgumentsSpec $arguments_spec The arguments specification
  * @param array         $parsed_args    data parsed by the ArgumentsParser
  *
  * @return array argument values by long option name
  */
 protected function extractAllLongOpts(ArgumentsSpec $arguments_spec, $parsed_args)
 {
     $long_opts = array();
     foreach ($parsed_args['options'] as $option_name => $value) {
         if ($long_option_name = $arguments_spec->normalizeOptionName($option_name)) {
             $long_opts[$long_option_name] = $value;
         }
     }
     return $long_opts;
 }