*! Version 1.0   14 May 2003 N.Cox
*! Version 1.1   15 Oct 2003 N.Orsini
*! Version 1.2   26 Mar 2004 N.Orsini & R.Bellocco
*! Version 1.3   31 Mar 2004 N.Orsini
*! Version 1.4   27 Nov 2004 N.Orsini

capture program drop pnrcheck
program pnrcheck, rclass

	version 8

	syntax varname [if] [in] [, SAVEPnr(string) SAVEInd(string) DIsplay LISTWrong LISTMissing]

// CHECK THE OPTIONS

	if  "`savepnr'"  != "" {
					local pnrname   "`savepnr'"
					}

	if  "`saveind'"  != "" {
					local pnrind   "`saveind'"
					}

// to use the option if/in

marksample touse, strok novarlist

// CHECK THE STORAGE TYPE OF PNR

local sttype : type `varlist'
local stcheck = substr("`sttype'",1,3)

if "`stcheck'" != "str"  {
				 // convert the pnr_variable from numeric to string
				 tempvar pnrnumb

				 qui tostring `varlist'  , generate(`pnrnumb')  format(%14.0f)
				 local varlist = "`pnrnumb'"
				 }

// CHECK THE PNR VARIABLE

tempname CASE

	capture
		assert length(trim(`varlist')) == 9   ///
		| length(trim(`varlist')) == 10   ///
		| length(trim(`varlist')) == 11  ///
		| length(trim(`varlist')) == 12 ///
		| length(trim(`varlist')) == 13   ///

	if _rc != 0 {
			di as err "The lenght of the variable is not acceptable!"
			exit 198
			}
		else {
			if length(trim(`varlist')) == 9 {
				                            scalar `CASE' = 7
								    local l =  length(trim(`varlist'))
								   }

			if length(trim(`varlist')) == 10 {
				                            scalar `CASE' = 1
								    local l =  length(trim(`varlist'))
								   }
			if length(trim(`varlist')) == 12 {
				                            scalar `CASE' = 2
								    local l =  length(trim(`varlist'))
								   }
			if length(trim(`varlist')) == 11 {
				                            scalar `CASE' = 3
								    local l =  length(trim(`varlist'))
								   }
			if length(trim(`varlist')) == 13 {
				                            scalar `CASE' = 4
								    local l =  length(trim(`varlist'))
	   							  }
			}

	if `CASE' == 1  {
				checkcontent `varlist'
			     }

	if `CASE' == 2  {
				checkcontent `varlist'
				tempvar pnr10
				gen  `pnr10' = substr(`varlist',3,10)
				local varlist = "`pnr10'"
				* di as err "Be careful pnr_variable is `l' characters, I work with the last 10"
		 		}

	if `CASE' == 3    {
				local sign = substr(`varlist',`l'-4,1)
				if "`sign'" == "-" {
									tempvar pnr11A pnr11B
									gen str6 `pnr11A' = substr(`varlist',1,`l'-5)
									gen str4 `pnr11B' = substr(`varlist',`l'-3,4)
									local varlist = "`pnr11A'+`pnr11B'"
									checkcontent `varlist'
									}
				}

	if  `CASE' == 4  {

				local sign = substr(`varlist',`l'-4,1)
				if "`sign'" == "-" {
									tempvar pnr11A pnr11B
									gen str6 `pnr11A' = substr(`varlist',3,`l'-5)
									gen str4 `pnr11B' = substr(`varlist',`l'-3,4)
									local varlist = "`pnr11A'+`pnr11B'"
									checkcontent `varlist'
									}
				}


	if  `CASE' == 7  {
				checkcontent `varlist'
				}


// CREATE 9 local macros ranging from 1 to 9

	tokenize 2 1 2 1 2 1 2 1 2

  quietly {
		tempvar pnr chk digit result sum length correct bad correct1 correct2 pnrcorrect
		generate `pnr' = trim(`varlist')
		char `pnr'[varname] "input_pnr"
		generate `chk' = real(substr(`pnr',10,1))
		char `chk'[varname] "i_check"

		generate byte `digit' = .
		generate `result' = ""
		generate `sum' = 0
            generate `pnrcorrect' = ""


    forval j = 1/9 {
			 replace `digit' = real(substr(`pnr',`j',1))
			 replace `result' = `result' + string(`digit' * ``j'')
 			}

		generate `length' = length(`result')
		local len = substr("`: type `result''",4,.)

		forval j = 1/`len' {
					replace `sum' = `sum' + real(substr(`result',`j',1)) ///
					if `j' <= `length' & `touse'
					}

		generate byte `correct' = mod(10 - mod(`sum',10),10)
		char `correct'[varname] "o_check"
		generate byte `bad' = `chk' != `correct'   & `chk' != . & `touse'

 					qui generate `correct1'  =  substr(`pnr',1,9)
					qui generate `correct2' =   string(`correct')
					qui replace `pnrcorrect' = `correct1' + `correct2'
					char `pnrcorrect'[varname] "output_pnr"
	}


	if "`savepnr'"  != "" {
					qui gen  `pnrname' =   `pnrcorrect'
 					}

	if "`saveind'"  != "" {
					gen byte `pnrind' = `bad'
					replace `pnrind' = 2 if `chk' == .
 					}

		qui count if `bad' == 1
		scalar NWRONG = r(N)
		qui count if `chk' == .
		scalar NMISS = r(N)

		scalar NOBS = c(N)
		scalar NRIGHT = NOBS-NWRONG-NMISS

		return scalar N = NOBS
		return scalar pnrwrong = NWRONG
		return scalar pnrright = NRIGHT

	if "`display'"  != "" {

		noi di in smcl _n _col(2) in gr "Check digit"  _col(16) "Obs"  _col(25) "Perc.(%)"
		noi di in smcl in gr "{hline 40}"
		noi di in smcl _col(2) in gr "Wrong"  _col(18) in y NWRONG _col(26) %3.1f (NWRONG/NOBS)*100
		noi di in smcl _col(2) in gr "Right"  _col(18) in y  NRIGHT _col(26) %3.1f (NRIGHT/NOBS)*100
		noi di in smcl _col(2) in gr "Missing"  _col(18) in y  NMISS _col(26) %3.1f (NMISS/NOBS)*100
		noi di in smcl in gr "{hline 40}"
		noi di in smcl _col(2) in gr "Total"  _col(18) in y  NOBS _col(26) %3.1f ((NRIGHT+NWRONG+NMISS)/NOBS)*100
 			}

	if "`listwrong'"  != "" {
	            	 list `pnr' `chk' `pnrcorrect' `correct' if `bad'    , subvarname sep(0)
 				 }

	if "`listmissing'"  != "" {
	            	 list `pnr' `chk' `pnrcorrect' `correct' if `chk' ==.    , subvarname sep(0)
 				 }

end

capture program drop checkcontent
program checkcontent
args varlist
capture assert real(`varlist') < .

	if _rc !=0 {
			di as err "`varlist' contains non-numeric characters"
			exit 7
			}
end