*******************************************************************************
* map.ado
* version 5.0

* Dictionaries can be defined on any Stata frame.
* Optionally install -dict- to facilitate the creation of dictionaries:
* ssc install dict

* author: Daniel Alves Fernandes
* contact: daniel.fernandes@eui.eu
*******************************************************************************

capture: program drop map
program define map

syntax varlist, DICTionary(string) [Values(string)]

  version 16

  confirm frame `dictionary'
  quietly: frame
  local current_frame: display "`r(currentframe)'"
  if ("`dictionary'" == "`current_frame'"){
    n: display as error ///
    "map cannot run when the dictionary list is in the active frame"
    exit 198
  }

  frame `dictionary': confirm variable `varlist'
  quietly frame `dictionary': ds `varlist', not
  local notkeys: display r(varlist)
  local size: list sizeof not_keys
  if("`values'" == ""){
    if (`size' == 0){
      n: display as error "frame `dictionary' does not contain values"
      exit 498
    }
    if (`size' > 1){
      n: display as error "ambiguous values column in frame `dictionary'"
      exit 498
    }
    else local values `not_keys'
  }
  if("`values'" != ""){
    frame `dictionary': confirm variable `values'
  }
  confirm new variable `values'

  quietly: ds `varlist', not(type string int)
  if ("`r(varlist)'" != ""){
    n: display as error "matching variables must be strings or integers"
    exit 109
  }
  foreach type in string int{
      quietly: ds `varlist', has(type `type')
      local `type'_in_current_frame: display r(varlist)
      quietly frame `dictionary': ds `varlist', has(type `type')
      local `type'_in_dict_frame: display r(varlist)
      local `type'_eq: list `type'_in_current_frame === `type'_in_dict_frame
  }
  if (`string_eq' == 0) | (`int_eq' == 0){
    display as error "type mismatch in matching variables"
    exit 109
  }

  tempvar dict_link
  capture: frlink m:1 `varlist', frame(`dictionary') gen(`dict_link')
  if (_rc != 0){
    n: display as error ///
    "the matching variables do not uniquely identify observations"
    exit
    498
  }

  quietly: frget `values', from(`dict_link')
  local match_size: list sizeof varlist
  if (`match_size' == 1) order `values', after(`varlist')
end