local cancel = param.get("cancel") and true or false
if cancel then return end

local issue = Issue:new_selector():add_where{ "id = ?", param.get("issue_id", atom.integer) }:for_share():single_object_mode():exec()

-- TODO patch for project voting
if config.alternative_voting and config.alternative_voting[tostring(issue.policy.id)] then
  return false
end


local preview = (param.get("preview") or param.get("edit")) and true or false

if not app.session.member:has_voting_right_for_unit_id(issue.area.unit_id) then
  return execute.view { module = "index", view = "403" }
end

local update_comment = param.get("update_comment") and true or false

if issue.state ~= "voting" and not issue.closed then
  slot.put_into("error", _"Voting has not started yet.")
  return false
end

if (issue.phase_finished or issue.closed) and preview then
  return
end

if issue.phase_finished or issue.closed and not update_comment then
  slot.put_into("error", _"This issue is already closed.")
  return false
end

local direct_voter = DirectVoter:by_pk(issue.id, app.session.member_id)

if param.get("discard", atom.boolean) then
  if direct_voter then
    direct_voter:destroy()
  end
  slot.put_into("notice", _"Your vote has been discarded. Delegation rules apply if set.")
  return
end

local move_up 
local move_down

local tempvoting_string = param.get("scoring")

local tempvotings = {}
if not update_comment then
  for match in tempvoting_string:gmatch("([^;]+)") do
    for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
      tempvotings[tonumber(initiative_id)] = tonumber(grade)
      if param.get("move_up_" .. initiative_id .. ".x", atom.integer) then
        move_up = tonumber(initiative_id)
      elseif param.get("move_down_" .. initiative_id .. ".x", atom.integer) then
        move_down = tonumber(initiative_id)
      end
    end
  end
end

if not move_down and not move_up then
  if not preview then
    if not direct_voter then
      if issue.closed then
        slot.put_into("error", _"This issue is already closed.")
        return false
      else 
        direct_voter = DirectVoter:new()
        direct_voter.issue_id = issue.id
        direct_voter.member_id = app.session.member_id
        direct_voter:save()

        direct_voter = DirectVoter:by_pk(issue.id, app.session.member_id)
      end
    end
    
    local formatting_engine
    if config.enforce_formatting_engine then
      formatting_engine = config.enforce_formatting_engine
    else
      formatting_engine = param.get("formatting_engine")
      local formatting_engine_valid = false
      for i, fe in ipairs(config.formatting_engines) do
        if formatting_engine == fe.id then
          formatting_engine_valid = true
        end
      end
      if not formatting_engine_valid then
        slot.put_into("error", "invalid formatting engine!")
        return false
      end
    end

    local comment = param.get("comment")

    if comment ~= direct_voter.comment then
      if #comment > 0 then
        direct_voter.formatting_engine = formatting_engine
        direct_voter.comment = comment
        if issue.closed then
          direct_voter.comment_changed = 'now'
        end
        direct_voter:render_content(true)
      else
        direct_voter.formatting_engine = null
        direct_voter.comment = null
        if issue.closed then
          direct_voter.comment_changed = 'now'
        end
      end
    end
    direct_voter:save()
    
  end

  if not update_comment then
    local scoring = param.get("scoring")

    for initiative_id, grade in scoring:gmatch("([^:;]+):([^:;]+)") do
      local initiative_id = tonumber(initiative_id)
      local grade = tonumber(grade)
      local initiative = Initiative:by_id(initiative_id)
      if initiative.issue.id ~= issue.id then
        return execute.view { module = "index", view = "403" }
      end
      if not preview and not issue.closed then
        local vote = Vote:by_pk(initiative_id, app.session.member.id)
        if not vote then
          vote = Vote:new()
          vote.issue_id = issue.id
          vote.initiative_id = initiative.id
          vote.member_id = app.session.member.id
        end
        vote.grade = grade
        vote:save()
      end
    end
  end

  if not preview and not cancel then
    request.redirect{
      module = "issue",
      view = "show",
      id = issue.id
    }
  end

else

  local current_initiative_id = move_up or move_down

  local current_grade = tempvotings[current_initiative_id] or 0
  local is_alone = true
  if current_grade == 0 then
    is_alone = false
  else
    for initiative_id, grade in pairs(tempvotings) do
      if current_initiative_id ~= initiative_id and grade == current_grade then
        is_alone = false
        break
      end
    end
  end

  if     move_up   and current_grade >= 0 and     is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade > current_grade then
        tempvotings[initiative_id] = grade - 1
      end
    end

  elseif move_up   and current_grade >= 0 and not is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade > current_grade then
        tempvotings[initiative_id] = grade + 1
      end
    end
    tempvotings[current_initiative_id] = current_grade + 1

  elseif move_up   and current_grade  < 0 and     is_alone then
    tempvotings[current_initiative_id] = current_grade + 1
    for initiative_id, grade in pairs(tempvotings) do
      if grade < current_grade then
        tempvotings[initiative_id] = grade + 1
      end
    end

  elseif move_up   and current_grade  < 0 and not is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade <= current_grade then
        tempvotings[initiative_id] = grade - 1
      end
    end
    tempvotings[current_initiative_id] = current_grade

  elseif move_down and current_grade <= 0 and     is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade < current_grade then
        tempvotings[initiative_id] = grade + 1
      end
    end

  elseif move_down and current_grade <= 0 and not is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade < current_grade then
        tempvotings[initiative_id] = grade - 1
      end
    end
    tempvotings[current_initiative_id] = current_grade - 1

  elseif move_down and current_grade  > 0 and     is_alone then
    tempvotings[current_initiative_id] = current_grade - 1
    for initiative_id, grade in pairs(tempvotings) do
      if grade > current_grade then
        tempvotings[initiative_id] = grade - 1
      end
    end

  elseif move_down and current_grade  > 0 and not is_alone then
    for initiative_id, grade in pairs(tempvotings) do
      if grade >= current_grade then
        tempvotings[initiative_id] = grade + 1
      end
    end
    tempvotings[current_initiative_id] = current_grade

  end

  local tempvotings_list = {}
  for key, val in pairs(tempvotings) do
    tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
  end

  tempvoting_string = table.concat(tempvotings_list, ";")

  request.redirect{
    module = "vote",
    view = "list",
    params = {
      issue_id = issue.id,
      scoring = tempvoting_string
    }
  }

end
