||| Copyright (C) 1998-2007, Sumisho Computer Systems Corp.  All Rights Reserved.
|||
||| Maintained by: Curl Solutions
{curl 6.0 applet}
{curl-file-attributes character-encoding = "utf8"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

{import * from COM.CURL.TRAINING.EXAMPLES.SUPPORT}
{import * from CURL.GUI.CHARTS}

|| Description:
|| Combine ctBaseTrainingApplicationLayout and ctBaseTrainingApplicationModel into a 
|| single class that provides presentations of data from the orders RecordSet
|| co-ordinated by the selected order id through the use of event handling.
||
|| Order change is communicated through use of the ctOrderIdChangedEvent - generated
|| from the method note-order-id-changed, and is handled by handle-order-id-changed.
||
|| Defines
|| exBaseTrainingApplication - the controlling application class combining the layout and model manager funtionality
||
|| Uses
|| ctOrderIdChangedEvent
|| ctBaseTrainingApplicationLayout
|| ctBaseTrainingApplicationModel
|| ct-filter
|| ct-date-sorter
|| ct-10-orders-RecordSet
|| ctContentPane
|| ctContentContainer
|| ct-totals-bar-chart
|| ct-order-pie-chart
|| ct-order-totals-from-view
|| ctOrderNode

|| This is the controlling class for the application. It inherits from both ctBaseTrainingApplicationLayout
|| and ctBaseTrainingApplicationModel to get layoput and data management functions.
{define-class public exBaseTrainingApplication 
  {inherits
    ctBaseTrainingApplicationLayout,
    ctBaseTrainingApplicationModel
  }
  
  || presentations
  field public pie-chart:Graphic
  field public date-chart:Graphic

  || view for a date range
  field public date-view:RecordView
  
  || Cont\structor takes a layout and a RecordView as input.
  {constructor public {default
                          app-layout:Graphic,
                          app-data:RecordView,
                          
                          index-field:String = "customer",
                          index-node-action:#{proc-type {ctOrderNode}:void} = null,
                          ...:EventHandler
                      }
    
    || instantiate as a ctBaseTrainingApplicationLayout
    {construct-super.ctBaseTrainingApplicationLayout
        layout = app-layout,
        {splice ...}
    }
    
    || instantiate as a ctBaseTrainingApplicationModel
    {construct-super.ctBaseTrainingApplicationModel
        app-data
    }
    
    set self.date-view = 
        {RecordView self.orders-view,
            sort = ct-date-sorter
        }
  
    || set the filter on the date-view to be the current order
    set self.date-view.filter = {ct-filter "order", 0}
    
    || create a PieChart 
    set self.pie-chart = 
        {self.make-PieChart-graphic 0, "date"}
    
    || create the chart
    set self.date-chart = 
        {self.make-Chart-graphic
            self.date-view,
            "date"
        }
    
    || initialize
    {self.initialize}
  }
  
  || This method initialitizes the applicaqtion with its presentations
  || add presentations
  {method public {initialize}:void
    
    {self.add-presentation "header",
        {HBox font-size = 14pt, width = {make-elastic}, height = 20pt,
            background = "#999966", {center {bold Curl Order Entry Sample}}
        }
    }
    
    {self.add-presentation "edit",    self.order-manager}
    {self.add-presentation "index",   self.order-index}
    {self.add-presentation "chart",   self.date-chart}
    {self.add-presentation "data",    self.orders-grid}
    {self.add-presentation "summary", self.pie-chart}
    
    {self.add-event-handler
        || handle a change of the current order id
        {on e:ctOrderIdChangedEvent at app-target:exBaseTrainingApplication do
            {app-target.handle-order-id-changed e}
        }
    }
    
    || initialize to the first purchase order
    {if self.orders-view.size > 0 then
        let order-id:int = self.orders-view[0].order
        {self.note-order-id-changed order-id}
    }
  }  
  || called to handle a change in the order id
  {method public {handle-order-id-changed e:ctOrderIdChangedEvent}:void
    
    || reset presentation order id
    set self.order-id = e.order-id
  
    || filter the date view +/- 2 days around the date
    {if-non-null record = {self.find-record e.order-id} then
        let dt:DateTime = record["date"] asa DateTime
        set self.date-view.filter = 
            {RecordFilter
                {proc {f-rec:Record}:bool
                    let f-date:DateTime = f-rec["date"] asa DateTime
                    {return
                        f-date >= dt - 2days and
                        f-date <= dt + 2days
                    }
                }
            }
    }
    
    || replace the Chart
    {self.add-presentation "chart",
        {self.make-Chart-graphic 
            pie-set-inner-margin = 5px,
            legend-enabled? = false,
            self.date-view,
            "price"
        }
    }
    || replace the PieChart
    {self.add-presentation "summary",
        {self.make-PieChart-graphic e.order-id, "date",
            pie-set-inner-margin = 5px,
            legend-enabled? = false
        }
    }
    
    || replace the report
    {self.add-presentation "report",
        {self.make-customer-order-report
            e.order-id
        }
    }
  }
  
  || Signal a change
  {method public {note-order-id-changed order-id:int}:void
    {self.enqueue-event
        {ctOrderIdChangedEvent 
            order-id
        }
    }
  }
  
  || find a record associated with the order-id
  {method public {find-record order-id:int}:#Record
    let index:int = 
        {self.orders-view.find
            {ct-filter "order", order-id}
        }
    
    {if index >= 0 then
        {return
            self.orders-view[index]
        }
     else
        {return null}
    }
  }
  
  || find a record associated with the order-id
  {method public {find-record-date date:DateTime}:#Record
    let index:int = 
        {self.orders-view.find
            {ct-filter "date", date}
        }
    
    {if index >= 0 then
        {return
            self.orders-view[index]
        }
     else
        {return null}
    }
  }
  
  ||-------------------------------------------------------------------------------------||
  || create chart
  {method public {make-Chart-graphic 
                     data-view:RecordView, 
                     field-name:String, 
                     ...
                 }:Graphic 
    
    || derive the totals view
    let totals-recordview:RecordView = 
        {RecordView
            || ensure the dates are sorted
            sort = ct-date-sorter,
            {ct-order-totals-from-view data-view, field-name = field-name}
        }
    
    || make a totals chart
    let chart:LayeredChart =
        {ct-totals-bar-chart totals-recordview, 
            || handle a user selection of a bar
            {on e:ctRecordDrilldownEvent do
                || find any line item record for the date selected
                let record:#Record =
                    {self.find-record-date
                        e.record["date"] asa DateTime
                    }
                || popup an interactive Pie for the date
                {if-non-null record then
                    {popup-message
                        width = 8cm, height = 8cm,
                        {ShapeBox
                            width = {add-stretch},
                            height = {add-stretch},
                            {ct-order-pie-chart
                                record
                            }
                        }
                    }
                }
            }
        }
    
    || add the drilldown function to the chart
    {if chart.layers.size >= 1 then
        set (chart.layers[0] asa BarLayer).shape-factory = ct-totals-drilldown-bar-factory
    }
    
    
    {return
        {ShapeBox
            || the ShapeBox will stretch to fill the container, and stretch the chart with it.
            width = {add-stretch},
            height = {add-stretch},
            chart
        }
    } 
  }
  
  
  || return a PieChart that is based all records sharing values the specified field
  || with the record corresponding to the order-id
  {method public {make-PieChart-graphic order-id:int, field-name:String, ...}:Graphic
    {if-non-null record = {self.find-record order-id} then
        {return
            {ShapeBox
                width = {add-stretch},
                height = {add-stretch},
                {ct-order-pie-chart
                    record,
                    {splice ...}
                }
            }
        }        
     else
        {return
            {PieChart}
        }
    }    
  }
} || exBaseTrainingApplication


{define-proc public {lcl-make-layout}:Graphic
    || Double-click on the title bar of a pane causes a ctPaneTitleEvent
    || to be handled on the title bar. Use this to pop-out a pane into a Dialog window.
    || Closing the winow returns the pane to its position.
    let e-pane:ctContentPane =
        {ctContentPane name = "edit",  title = {bold edit}}
    
    {e-pane.title-bar.add-event-handler
        {on e:ctPaneTitleEvent do
            {if not e.pane.maximized? then
                || prevent the action from recurring
                set e.pane.maximized? = true
                || placeholder for the pane
                let f:Fill = {Fill}
                {e.pane.replace-with f}
                || the popup is modal - the application cannot continue until the window is closeds
                let status:String =
                    {popup-message
                        title = "Edit - close this window to continue",
                        {Frame
                            width = 16cm, height = 12cm,
                            e.pane
                        }
                    }
                || restore the pane
                {f.replace-with e.pane}
                set e.pane.maximized? = false
            }
        }
    }
    
    || use a maximizing layout for some of the content
    let max-layout:ctContentContainer = 
        {ctContentContainer width = 20cm, height = 16cm, background = "white"}
    
    {max-layout.add 
        {HBox
            {VBox
                {max-layout.pane-factory "chart",  
                    title = {bold chart}
                },
                {max-layout.pane-factory "data", 
                    title = {bold data}
                }
            },
            {VBox
                {max-layout.pane-factory  "report",  
                    title = {bold report}
                },
                {max-layout.pane-factory  "summary", 
                    title = {bold active summary}
                }
            } 
        }
    }
    
    || index pane
    let index-pane:ctContentPane =
        {ctContentPane 
            height = 16cm, width = 4cm, 
            title = {bold index},
            content = {ScrollBox name = "index"}
        }
    
    set index-pane.content-frame.halign = "origin"
    set index-pane.content-frame.valign = "origin"
    
    || make a layout
    let training-layout:Frame =
        {Frame
            {ctVBox
                height = 16cm,
                halign = "center",
                {HBox name = "header"},
                {HBox
                    valign = "top",
                    spacing = 10px, margin = 5px,
                    index-pane,
                    {TabContainer
                        tab-placement = TabPlacement.right,
                        {TabPane
                            margin = 10px,
                            background = "#CCCC99",
                            label = {bold Edit}, 
                            e-pane
                        },
                        {TabPane
                            label = {bold Data},
                            margin = 10px,
                            background = "#CCCC99",
                            max-layout
                        }
                    }
                    
                },
                {HBox name = "footer"}
            }
        }   
    
    {return training-layout} 
}

{value 

    || create and display the appliction class and assign the layout and data
    let app:exBaseTrainingApplication =
        {exBaseTrainingApplication
            {lcl-make-layout},
            {RecordView {ct-10-orders-RecordSet}}
        }
    
    app

}





