#  Phusion Passenger - https://www.phusionpassenger.com/
#  Copyright (c) 2017 Phusion Holding B.V.
#
#  "Passenger", "Phusion Passenger" and "Union Station" are registered
#  trademarks of Phusion Holding B.V.
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.

# This file uses the cxxcodebuilder API. Learn more at:
# https://github.com/phusion/cxxcodebuilder

require 'phusion_passenger/nginx/config_options'

def main
  set_indent_string '    '
  comment copyright_header_for(__FILE__), 1

  separator

  comment %q{
    ConfigGeneral/AutoGeneratedSetterFuncs.c is automatically generated from
    ConfigGeneral/AutoGeneratedSetterFuncs.c.cxxcodebuilder,
    using definitions from src/ruby_supportlib/phusion_passenger/nginx/config_options.rb.
    Edits to ConfigGeneral/AutoGeneratedSetterFuncs.c will be lost.

    To update ConfigGeneral/AutoGeneratedSetterFuncs.c:
      rake nginx

    To force regeneration of ConfigGeneral/AutoGeneratedSetterFuncs.c:
      rm -f src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c
      rake src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c
  }

  separator

  function 'static void record_main_conf_source_location(ngx_conf_t *cf, ngx_str_t *file, ngx_uint_t *line)', %Q{
    if (cf->conf_file == NULL) {
      file->data = (u_char *) NULL;
      file->len = 0;
      *line = 0;
    } else if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
      file->data = (u_char *) "(command line)";
      file->len = sizeof("(command line)") - 1;
      *line = 0;
    } else {
      *file = cf->conf_file->file.name;
      *line = cf->conf_file->line;
    }
  }

  function 'static void record_loc_conf_source_location(ngx_conf_t *cf, passenger_loc_conf_t *pl_conf, ngx_str_t *file, ngx_uint_t *line)', %Q{
    pl_conf->cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
    pl_conf->clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    if (cf->conf_file == NULL) {
      file->data = (u_char *) NULL;
      file->len = 0;
      *line = 0;
    } else if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
      file->data = (u_char *) "(command line)";
      file->len = sizeof("(command line)") - 1;
      *line = 0;
    } else {
      *file = cf->conf_file->file.name;
      *line = cf->conf_file->line;
    }
  }

  separator

  ctx = self
  NGINX_CONFIGURATION_OPTIONS.each do |option|
    next if option[:alias_for] || option[:function]

    function(setter_function_declaration_for(option)) do
      setter_function_body_for(option)
    end
  end
end

def setter_function_declaration_for(option)
  function_name = "passenger_conf_set_" + option[:name].sub(/^passenger_/, '')
  "static char *#{function_name}(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)"
end

def setter_function_body_for(option)
  case option[:type]
  when :string
    raw_setter = "ngx_conf_set_str_slot"
  when :integer, :uinteger
    raw_setter = "ngx_conf_set_num_slot"
  when :flag
    raw_setter = "ngx_conf_set_flag_slot"
  when :string_array
    raw_setter = "ngx_conf_set_str_array_slot"
  when :string_keyval
    raw_setter = "ngx_conf_set_keyval_slot"
  when :path
    raw_setter = "ngx_conf_set_path_slot"
  when :msec
    raw_setter = "ngx_conf_set_msec_slot"
  else
    raise "Unknown type #{option[:type].inspect} for option #{option[:name]}"
  end

  struct_field = struct_field_for(option)

  case option[:struct]
  when 'NGX_HTTP_LOC_CONF_OFFSET', nil
    conf_type = "passenger_loc_conf_t"
  when 'NGX_HTTP_MAIN_CONF_OFFSET'
    conf_type = "passenger_main_conf_t"
  else
    raise "Unknown struct #{option[:struct].inspect}"
  end

  if conf_type == "passenger_loc_conf_t"
    add_code %Q{
      #{conf_type} *passenger_conf = conf;

      passenger_conf->autogenerated.#{struct_field}_explicitly_set = 1;
      record_loc_conf_source_location(cf, passenger_conf,
        &passenger_conf->autogenerated.#{struct_field}_source_file,
        &passenger_conf->autogenerated.#{struct_field}_source_line);
    }
    separator
  else
    add_code %Q{
      #{conf_type} *passenger_conf = conf;

      passenger_conf->autogenerated.#{struct_field}_explicitly_set = 1;
      record_main_conf_source_location(cf,
        &passenger_conf->autogenerated.#{struct_field}_source_file,
        &passenger_conf->autogenerated.#{struct_field}_source_line);
    }
    separator
  end

  add_code %Q{
    return #{raw_setter}(cf, cmd, conf);
  }
end

def struct_field_for(option)
  if option.has_key?(:field)
    result = option[:field]
  else
    result = option[:name].sub(/^passenger_/, '')
  end
  result.gsub('.', '_')
end

main
