diff --git a/data/test.kch b/data/test.kch
index fda994069..ded3f7961 100644
Binary files a/data/test.kch and b/data/test.kch differ
diff --git a/timespans/callcost.go b/timespans/callcost.go
new file mode 100644
index 000000000..1fd3daf56
--- /dev/null
+++ b/timespans/callcost.go
@@ -0,0 +1,58 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2012 Radu Ioan Fericean
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+package timespans
+
+import (
+ "fmt"
+ "reflect"
+)
+
+/*
+The output structure that will be returned with the call cost information.
+*/
+type CallCost struct {
+ TOR, CstmId, Subject, DestinationPrefix string
+ Cost, ConnectFee float64
+ Timespans []*TimeSpan
+}
+
+// Pretty printing for call cost
+func (cc *CallCost) String() (r string) {
+ r = fmt.Sprintf("%v[%v] : %s -> %s (", cc.Cost, cc.ConnectFee, cc.Subject, cc.DestinationPrefix)
+ for _, ts := range cc.Timespans {
+ r += fmt.Sprintf(" %v,", ts.GetDuration())
+ }
+ r += " )"
+ return
+}
+
+// Merges the received timespan if they are similar (same activation period, same interval, same minute info.
+func (cc *CallCost) Merge(other *CallCost) *CallCost {
+ ts := cc.Timespans[len(cc.Timespans)-1]
+ otherTs := other.Timespans[0]
+ if reflect.DeepEqual(ts.ActivationPeriod, otherTs.ActivationPeriod) &&
+ reflect.DeepEqual(ts.MinuteInfo, otherTs.MinuteInfo) && reflect.DeepEqual(ts.Interval, otherTs.Interval) {
+ cc.Cost += other.Cost
+ // extend the last timespan with
+ ts.TimeEnd = ts.TimeEnd.Add(otherTs.GetDuration())
+ // add the rest of the timspans
+ cc.Timespans = append(cc.Timespans, other.Timespans[1:]...)
+ return nil
+ }
+ return other
+}
diff --git a/timespans/callcost_test.go b/timespans/callcost_test.go
new file mode 100644
index 000000000..d123bd94a
--- /dev/null
+++ b/timespans/callcost_test.go
@@ -0,0 +1,113 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2012 Radu Ioan Fericean
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package timespans
+
+import (
+ // "log"
+ "testing"
+ "time"
+)
+
+func TestSingleResultMerge(t *testing.T) {
+ getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
+ defer getter.Close()
+ t1 := time.Date(2012, time.February, 2, 17, 00, 0, 0, time.UTC)
+ t2 := time.Date(2012, time.February, 2, 17, 01, 0, 0, time.UTC)
+ cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc1, _ := cd.GetCost()
+ if cc1.Cost != 12 {
+ t.Errorf("expected 12 was %v", cc1.Cost)
+ }
+ t1 = time.Date(2012, time.February, 2, 17, 01, 0, 0, time.UTC)
+ t2 = time.Date(2012, time.February, 2, 17, 02, 0, 0, time.UTC)
+ cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc2, _ := cd.GetCost()
+ if cc2.Cost != 12 {
+ t.Errorf("expected 12 was %v", cc2.Cost)
+ }
+ result := cc1.Merge(cc2)
+ if result != nil {
+ t.Error("expected nil result")
+ }
+ if len(cc1.Timespans) != 1 || cc1.Timespans[0].GetDuration().Seconds() != 120 {
+ t.Error("wrong resulted timespan")
+ }
+ if cc1.Cost != 24 {
+ t.Errorf("Exdpected 24 was %v", cc1.Cost)
+ }
+}
+
+func TestMultipleResultMerge(t *testing.T) {
+ getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
+ defer getter.Close()
+ t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
+ t2 := time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC)
+ cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc1, _ := cd.GetCost()
+ if cc1.Cost != 12 {
+ t.Errorf("expected 12 was %v", cc1.Cost)
+ }
+ t1 = time.Date(2012, time.February, 2, 18, 00, 0, 0, time.UTC)
+ t2 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
+ cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc2, _ := cd.GetCost()
+ if cc2.Cost != 6 {
+ t.Errorf("expected 12 was %v", cc2.Cost)
+ }
+ result := cc1.Merge(cc2)
+ if result == nil {
+ t.Error("expected non nil result")
+ }
+ if len(cc1.Timespans) != 1 || cc1.Timespans[0].GetDuration().Seconds() != 60 {
+ t.Error("wrong resulted timespan")
+ }
+ if cc1.Cost != 12 {
+ t.Errorf("Exdpected 12 was %v", cc1.Cost)
+ }
+}
+
+func TestMultipleInputLeftMerge(t *testing.T) {
+ getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10)
+ defer getter.Close()
+ t1 := time.Date(2012, time.February, 2, 17, 59, 0, 0, time.UTC)
+ t2 := time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
+ cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc1, _ := cd.GetCost()
+ if cc1.Cost != 18 {
+ t.Errorf("expected 12 was %v", cc1.Cost)
+ }
+ t1 = time.Date(2012, time.February, 2, 18, 01, 0, 0, time.UTC)
+ t2 = time.Date(2012, time.February, 2, 18, 02, 0, 0, time.UTC)
+ cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
+ cc2, _ := cd.GetCost()
+ if cc2.Cost != 6 {
+ t.Errorf("expected 12 was %v", cc2.Cost)
+ }
+ result := cc1.Merge(cc2)
+ if result != nil {
+ t.Error("expected nil result")
+ }
+ if len(cc1.Timespans) != 2 || cc1.Timespans[1].GetDuration().Seconds() != 120 {
+ t.Error("wrong resulted timespan")
+ t.Log(cc1.Timespans[1].GetDuration())
+ }
+ if cc1.Cost != 24 {
+ t.Errorf("Exdpected 24 was %v", cc1.Cost)
+ }
+}
diff --git a/timespans/calldesc.go b/timespans/calldesc.go
index f8cae822a..ed2db05c5 100644
--- a/timespans/calldesc.go
+++ b/timespans/calldesc.go
@@ -224,25 +224,6 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) {
return cc, err
}
-/*
-The output structure that will be returned with the call cost information.
-*/
-type CallCost struct {
- TOR, CstmId, Subject, DestinationPrefix string
- Cost, ConnectFee float64
- Timespans []*TimeSpan
-}
-
-// Pretty printing for call cost
-func (cc *CallCost) String() (r string) {
- r = fmt.Sprintf("%v[%v] : %s -> %s (", cc.Cost, cc.ConnectFee, cc.Subject, cc.DestinationPrefix)
- for _, ts := range cc.Timespans {
- r += fmt.Sprintf(" %v,", ts.GetDuration())
- }
- r += " )"
- return
-}
-
/*
Returns the cost of a second in the present time conditions.
*/
diff --git a/timespans/intervals.go b/timespans/interval.go
similarity index 100%
rename from timespans/intervals.go
rename to timespans/interval.go
diff --git a/timespans/timespans.go b/timespans/timespans.go
index af3011c61..14366533f 100644
--- a/timespans/timespans.go
+++ b/timespans/timespans.go
@@ -20,8 +20,8 @@ package timespans
import (
"fmt"
+ // "log"
"time"
- //"log"
)
/*
@@ -81,7 +81,7 @@ func (ts *TimeSpan) Contains(t time.Time) bool {
}
/*
-will set the interval as spans's interval if new ponder is greater then span's interval ponder
+Will set the interval as spans's interval if new ponder is greater then span's interval ponder
or if the ponders are equal and new price is lower then spans's interval price
*/
func (ts *TimeSpan) SetInterval(i *Interval) {