package services import ( "strconv" "strings" ) // StateToClimateRegion maps US state abbreviations to IECC climate zone IDs. // Some states span multiple zones — this uses the dominant zone for the most populated areas. var StateToClimateRegion = map[string]uint{ // Zone 1: Hot-Humid "HI": 1, "FL": 1, "LA": 1, // Zone 2: Hot-Dry / Hot-Humid mix "TX": 2, "AZ": 2, "NV": 2, "NM": 2, // Zone 3: Mixed-Humid "GA": 3, "SC": 3, "AL": 3, "MS": 3, "AR": 3, "NC": 3, "TN": 3, "OK": 3, "CA": 3, // Zone 4: Mixed "VA": 4, "KY": 4, "MO": 4, "KS": 4, "DE": 4, "MD": 4, "DC": 4, "WV": 4, "OR": 4, // Zone 5: Cold "NJ": 5, "PA": 5, "CT": 5, "RI": 5, "MA": 5, "OH": 5, "IN": 5, "IL": 5, "IA": 5, "NE": 5, "CO": 5, "UT": 5, "WA": 5, "ID": 5, "NY": 5, "MI": 5, // Zone 6: Very Cold "WI": 6, "MN": 6, "ND": 6, "SD": 6, "MT": 6, "WY": 6, "VT": 6, "NH": 6, "ME": 6, // Zone 8: Arctic "AK": 8, } // GetClimateRegionIDByState returns the climate region ID for a US state abbreviation. // Returns 0 if the state is not found. func GetClimateRegionIDByState(state string) uint { regionID, ok := StateToClimateRegion[strings.ToUpper(strings.TrimSpace(state))] if !ok { return 0 } return regionID } // ZipToState maps a US ZIP code to a state abbreviation using the 3-digit ZIP prefix. // Returns empty string if the ZIP is invalid or unrecognized. func ZipToState(zip string) string { zip = strings.TrimSpace(zip) if len(zip) < 3 { return "" } prefix, err := strconv.Atoi(zip[:3]) if err != nil { return "" } // ZIP prefix → state mapping (USPS ranges) switch { case prefix >= 10 && prefix <= 27: return "MA" case prefix >= 28 && prefix <= 29: return "RI" case prefix >= 30 && prefix <= 38: return "NH" case prefix >= 39 && prefix <= 49: return "ME" case prefix >= 50 && prefix <= 59: return "VT" case prefix >= 60 && prefix <= 69: return "CT" case prefix >= 70 && prefix <= 89: return "NJ" case prefix >= 100 && prefix <= 149: return "NY" case prefix >= 150 && prefix <= 196: return "PA" case prefix >= 197 && prefix <= 199: return "DE" case prefix >= 200 && prefix <= 205: return "DC" case prefix >= 206 && prefix <= 219: return "MD" case prefix >= 220 && prefix <= 246: return "VA" case prefix >= 247 && prefix <= 268: return "WV" case prefix >= 270 && prefix <= 289: return "NC" case prefix >= 290 && prefix <= 299: return "SC" case prefix >= 300 && prefix <= 319: return "GA" case prefix >= 320 && prefix <= 349: return "FL" case prefix >= 350 && prefix <= 369: return "AL" case prefix >= 370 && prefix <= 385: return "TN" case prefix >= 386 && prefix <= 397: return "MS" case prefix >= 400 && prefix <= 427: return "KY" case prefix >= 430 && prefix <= 458: return "OH" case prefix >= 460 && prefix <= 479: return "IN" case prefix >= 480 && prefix <= 499: return "MI" case prefix >= 500 && prefix <= 528: return "IA" case prefix >= 530 && prefix <= 549: return "WI" case prefix >= 550 && prefix <= 567: return "MN" case prefix >= 570 && prefix <= 577: return "SD" case prefix >= 580 && prefix <= 588: return "ND" case prefix >= 590 && prefix <= 599: return "MT" case prefix >= 600 && prefix <= 629: return "IL" case prefix >= 630 && prefix <= 658: return "MO" case prefix >= 660 && prefix <= 679: return "KS" case prefix >= 680 && prefix <= 693: return "NE" case prefix >= 700 && prefix <= 714: return "LA" case prefix >= 716 && prefix <= 729: return "AR" case prefix >= 730 && prefix <= 749: return "OK" case prefix >= 750 && prefix <= 799: return "TX" case prefix >= 800 && prefix <= 816: return "CO" case prefix >= 820 && prefix <= 831: return "WY" case prefix >= 832 && prefix <= 838: return "ID" case prefix >= 840 && prefix <= 847: return "UT" case prefix >= 850 && prefix <= 865: return "AZ" case prefix >= 870 && prefix <= 884: return "NM" case prefix >= 889 && prefix <= 898: return "NV" case prefix >= 900 && prefix <= 966: return "CA" case prefix >= 967 && prefix <= 968: return "HI" case prefix >= 970 && prefix <= 979: return "OR" case prefix >= 980 && prefix <= 994: return "WA" case prefix >= 995 && prefix <= 999: return "AK" default: return "" } }