// Version compatibility
*! version 1.2 10JULY2024  Masud Rahman

// Version compatibility
program version_tested
    syntax, [ QUIetly]
    if c(stata_version)<17 {
        `qui' display "Tested with Stata 17+: Some features may not work "
    }

end

program define pyramid_chart, rclass
    // Declare the syntax
syntax varlist(numeric) [if] [in], OVER(varname) ///
                                   BY(varname)   ///
                                   DEC(integer)  ///
                                   [QUIetly]     /// If version <17 give warning
                                   [bar1(str asis)]  /// Options for Bar1    
                                   [bar2(str asis)]  /// Options for Bar2
                                   [sctopt(str asis)] /// Options for Scatter TEXT
                                   [*]   //
    version_tested

    local num_var `varlist'
    local ycat_var `over'
    local xcat_var `by'

    // Extract the options and provide default values if not specified
    local decimal_place = 0
    if "`dec'" != "" {
        local decimal_place = real("`dec'")
    }

    // Capture any additional options
    local additional_options "`options'"

    // Check for the presence of variables
    if ("`num_var'" == "" | "`xcat_var'" == "" | "`ycat_var'" == "") {
        di as error "Please provide a numeric variable, and two categorical variables."
        exit 198
    }
    
    // Check Default Option for SCTopt
    if missing(`"`sctopt'"') local sctopt mlabcolor(gs0)
    
    // Debugging: Confirm variables are set correctly
    di "Numeric Variable: `num_var'"
    di "Y-Categorical Variable: `ycat_var'"
    di "X-Categorical Variable: `xcat_var'"

    // Find the label name assigned to xcat_var
    local labelname : value label `xcat_var'
    
    // Extract the labels for the xcat_var variable
    qui label list `labelname'

    // Extract the labels for the categories (assuming categories are 1 and 2 for simplicity)
    local left_label : label `labelname' 1
    local right_label : label `labelname' 2

    // Declare tempvars
    tempvar total_population population_pct population_pct_neg population_pct_left pct_left_label pct_right_label

    // Calculate the total `num_var` for each category
    egen `total_population' = total(`num_var'), by(`xcat_var')
    
    // Calculate the `num_var` percentage for each age group within each category
    gen `population_pct' = (`num_var' / `total_population') * 100
    
    // Create a variable for negative percentage for the pyramid
    qui gen `population_pct_neg' = -`population_pct' if `xcat_var' == 1
    qui replace `population_pct_neg' = `population_pct' if `xcat_var' == 2
    
    // Identify the unique age groups and store them in a local macro
    qui levelsof `ycat_var', local(agegroups)
    
    // Generate a variable for the absolute value of male `num_var` percentage for labels
    gen `population_pct_left' = abs(`population_pct_neg')

    // Create formatted label variables for the scatter plots
    qui gen str `pct_left_label' = string(`population_pct_left', "%9.`decimal_place'f")
    qui gen str `pct_right_label' = string(`population_pct', "%9.`decimal_place'f")

    // Calculate the maximum percentage value
    qui summarize `population_pct'
    local max_pct = ceil(r(max) / 10) * 10

    if `max_pct' > 6 {
        // Generate a list of x-axis labels from 0 to max_pct in increments of 5
        local xlabels
        forvalues i = 0(5)`max_pct' {
            local xlabels `xlabels' `i'
        }

        // Generate a list of negative x-axis labels from -max_pct to -5 in increments of 5
        local neg_xlabels
        forvalues i = -`max_pct'(5)-5 {
            local neg_xlabels `neg_xlabels' `i'
        }
    } 
	else {
        // Generate a list of x-axis labels from 0 to max_pct in increments of 1
        local xlabels
        forvalues i = 0(1)`max_pct' {
            local xlabels `xlabels' `i'
        }

        // Generate a list of negative x-axis labels from -max_pct to -1 in increments of 1
        local neg_xlabels
        forvalues i = -`max_pct'(1)-1 {
            local neg_xlabels `neg_xlabels' `i'
        }
    }

    // Combine the negative and positive labels, converting negative labels to positive for display
    local xlabel_list
    foreach label in `neg_xlabels' 0 `xlabels' {
        local abs_label = abs(`label')
        local xlabel_list `xlabel_list' `label' "`abs_label'"
    }

    // Plot the `num_var` pyramid with additional options
    twoway (bar `population_pct_neg' `ycat_var' if `xcat_var' == 1, horizontal base(0) `bar1' ) ///
           (bar `population_pct' `ycat_var'     if `xcat_var' == 2, horizontal base(0) `bar2' ) ///
           (scatter `ycat_var' `population_pct_neg' if `xcat_var' == 1, msymbol(i) `sctopt' mlab(`pct_left_label')  mlabp(9)) ///
           (scatter `ycat_var' `population_pct'     if `xcat_var' == 2, msymbol(i) `sctopt' mlab(`pct_right_label')  mlabp(3)), ///
           legend(order(1 "`left_label'" 2 "`right_label'")) ///
           ylabel(`agegroups', valuelabel angle(0)) ///
           xlabel(`xlabel_list', format(%3.0f)) ///
           `additional_options'
end