/*
 * Copyright 2010 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.drools.examples.broker

// importing classes
import org.drools.examples.broker.model.Company
import org.drools.examples.broker.model.StockTick
import org.drools.examples.broker.model.SuddenDropEvent

// it is possible to import static methods as functions for usage in the rules
import org.drools.examples.broker.misc.BrokerUtils

// a common pattern is to expose services to rules through
// a helper service class
global org.drools.examples.broker.BrokerServices services

// default dialect for the semantic code will be MVEL
dialect "mvel"
 
// tells the engine that a StockTick instance will assume the
// role (semantics) of events and that the default retention
// policy will be 2 minutes
declare StockTick
    @role( event )
    @expires( 2m )
end 

// an event declaration to represent situations
// where a sudden drop happens. In this case we are not
// defining any explicit expiration policy.
declare SuddenDropEvent
    @role( event )
end

// One can even declare helper facts to make rules easier and
// simpler to write and maintain
declare Statistics
    symbol : String @key()
    average : double
end
 
rule "Setup statistics"
when
   $c : Company( $s : symbol )
   not( Statistics( symbol == $s ) )
then
   Statistics s = new Statistics();
   s.symbol = $s;
   insert( s );
end

// a simple rule to show that it is possible to join
// events from an entry-point (stream) with facts
// present in the working memory
rule "Update stock price"
    agenda-group "evaluation"
    lock-on-active
when
    $cp : Company( $sb : symbol )
    $st : StockTick( symbol == $sb, $pr : price ) from entry-point "StockTick stream"
then
    // This shows an update on working memory facts with data from joined events
    modify( $cp ) { currentPrice = $pr }
    
    // Although events are considered immutable, a common pattern is to use a class
    // to represent an event and enrich that event instance with data derived from other facts/events.
    // Below we "enrich" the event instance with the percentual change in the price,
    // based on the previous price
    modify( $st ) { delta = $cp.delta }
end

// a low salience rule is used some times to change rule execution phases.
// in this case, it moves processing from "evaluation" to "report" phase.
rule "evaluation done"
    agenda-group "evaluation"
    salience -10
when
    StockTick( ) from entry-point "StockTick stream"
then
    drools.setFocus( "report" );
end

// this rule shows a trick to get the last available event as well as
// how to call global services from the consequence
rule "sudden drop"
    enabled true
    agenda-group "report"
when
    $st : StockTick( $sb : symbol, $ts : timestamp, $pr : price, $dt : delta < -0.05 ) from entry-point "StockTick stream"
    not( StockTick( symbol == $sb, timestamp > $ts ) from entry-point "StockTick stream" )
then
    services.log( "Drop >5%: "+$sb+" delta: "+ BrokerUtils.percent($dt)+" price: $"+$pr );
    
    // we also want to create an event and forward it into the engine to a predefined entry point
    // that is being listened by other rules
    with( sde = new SuddenDropEvent() ) {
        symbol = $sb,
        percent = $dt,
        timestamp = $ts
    }
    drools.getEntryPoint("Analysis Events").insert( sde );
end

