Skip to content

Commit

Permalink
New hierarchical geography model, no longer hardcoded
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeymckay committed Feb 6, 2014
1 parent 1624339 commit e616620
Show file tree
Hide file tree
Showing 21 changed files with 1,521 additions and 61 deletions.
6 changes: 3 additions & 3 deletions _attachments/app/app.coffee
Expand Up @@ -75,8 +75,8 @@ class Router extends Backbone.Router
@adminLoggedIn
success: ->
Coconut.HierarchyView = new HierarchyView()
if type is "ward"
Coconut.HierarchyView.class = WardHierarchy
if type is "geo"
Coconut.HierarchyView.class = GeoHierarchy
else if type is "facility"
Coconut.HierarchyView.class = FacilityHierarchy
Coconut.HierarchyView.render()
Expand Down Expand Up @@ -441,7 +441,7 @@ class Router extends Backbone.Router
$('#application-title').html Coconut.config.title()

# Only start app after Ward/Facility data has been loaded
classesToLoad = [FacilityHierarchy, WardHierarchy]
classesToLoad = [FacilityHierarchy, WardHierarchy, GeoHierarchy]

startApplication = _.after classesToLoad.length, ->
Coconut.loginView = new LoginView()
Expand Down
6 changes: 3 additions & 3 deletions _attachments/app/app.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions _attachments/app/models/Case.coffee
Expand Up @@ -93,7 +93,8 @@ class Case

# Don't use facility to identify district because they may be traveling
district: ->
district = WardHierarchy.district(@shehia()) if @shehia()?
GeoHierarchy.findOneShehia(@shehia())?.DISTRICT if @shehia()?

# Below is invalid, because it could use a facility's district, which would be wrong, so commenting out
#user = @user()
#if user? and not district?
Expand Down Expand Up @@ -128,7 +129,9 @@ class Case
return completionTime.diff(startTime, "days")

location: (type) ->
WardHierarchy[type](@toJSON()["Case Notification"]?["FacilityName"])
# Not sure how this works, since we are using the facility name with a database of shehias
#WardHierarchy[type](@toJSON()["Case Notification"]?["FacilityName"])
GeoHierarchy.findOneShehia(@toJSON()["Case Notification"]?["FacilityName"])?[type.toUpperCase()]

withinLocation: (location) ->
return @location(location.type) is location.name
Expand Down
8 changes: 4 additions & 4 deletions _attachments/app/models/Case.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 127 additions & 0 deletions _attachments/app/models/GeoHierarchy.coffee
@@ -0,0 +1,127 @@
#
class GeoHierarchy extends Backbone.Model
initialize: ->
@set
_id: "Geo Hierarchy"

url: "/geoHierarchy"

@levels = ["REGION","DISTRICT","SHEHIA"]

# ward_shehia_breakdown_by_constituan_district_region

# "REGION": {
# "DISTRICT": {
# "CONSTITUAN": [
# "WARD/ Shehia"
# ]
# }
# },
#
#


GeoHierarchy.load = (options) =>
geoHierarchy = new GeoHierarchy()
geoHierarchy.fetch
success: =>
GeoHierarchy.hierarchy = geoHierarchy.get("hierarchy")

GeoHierarchy.root = {
parent: null
}

# Adds properties region, district, shehia, etc to node
addLevelProperties = (node) ->
levelClimber = node
node[levelClimber.level] = levelClimber.name
while levelClimber.parent isnt null
levelClimber = levelClimber.parent
node[levelClimber.level] = levelClimber.name
return node

# builds the tree
addChildren = (node,values, levelNumber) =>
if _(values).isArray()
node.children = for value in values
result = {
parent: node
level: @levels[levelNumber]
name: value
children: null
}
result = addLevelProperties(result)
node
else
node.children = for key, value of values
result = {
parent:node
level: @levels[levelNumber]
name:key
}
result = addLevelProperties(result)
addChildren result, value, levelNumber+1
return node

addChildren(GeoHierarchy.root, GeoHierarchy.hierarchy, 0)

options.success()
error: (error) ->
console.error "Error loading Geo Hierarchy: #{error}"
options.error(error)


GeoHierarchy.findInNodes = (nodes, requiredProperties) ->
results = _(nodes).where requiredProperties

if _(results).isEmpty()
results = (for node in nodes
GeoHierarchy.findInNodes(node.children, requiredProperties)
) if nodes?
results = _.chain(results).flatten().compact().value()
return [] if _(results).isEmpty()

return results

GeoHierarchy.find = (name,level) ->
GeoHierarchy.findInNodes(GeoHierarchy.root.children, {name:name, level:level})

GeoHierarchy.findAllForLevel = (level) ->
GeoHierarchy.findInNodes(GeoHierarchy.root.children, {level: level})

GeoHierarchy.findChildrenNames = (targetLevel, parentName) ->
indexOfTargetLevel = _(@levels).indexOf(targetLevel)
parentLevel = @levels[indexOfTargetLevel-1]
nodeResult = GeoHierarchy.findInNodes(GeoHierarchy.root.children, {name:parentName, level:parentLevel})
return [] if _(nodeResult).isEmpty()
console.error "More than one match" if nodeResult.length > 2
return _(nodeResult[0].children).pluck "name"

# I think this is redundant-ish
GeoHierarchy.findAllDescendantsAtLevel = (name, sourceLevel, targetLevel) ->
sourceNode = GeoHierarchy.find(name, sourceLevel)

getLevelDescendants = (node) ->
return node if node.level is targetLevel
return (for childNode in node.children
getLevelDescendants(childNode)
)

_.flatten(getLevelDescendants sourceNode[0])

GeoHierarchy.findShehia = (targetShehia) ->
GeoHierarchy.find(targetShehia,"SHEHIA")

GeoHierarchy.findOneShehia = (targetShehia) ->
shehia = GeoHierarchy.findShehia(targetShehia)
switch shehia.length
when 0 then return null
when 1 then return shehia[0]
else
console.error "Multiple Shehia's found for #{targetShehia}"

GeoHierarchy.findAllShehiaNamesFor = (name, level) ->
_.pluck GeoHierarchy.findAllDescendantsAtLevel(name, level, "SHEHIA"), "name"

GeoHierarchy.allDistricts = ->
_.pluck GeoHierarchy.findAllForLevel("DISTRICT"), "name"

0 comments on commit e616620

Please sign in to comment.