(function($) {

var _tcColorPattern = ['#990033','#ff0066','#cc00cc','#6600cc','#3333ff','#003366','#009999','#00ff99',
                       '#009933','#00cc00','#ccff00','#ffcc00','#996633','#cc9966','#ff3366','#ff3399',
                       '#cc00ff','#9966ff','#3333cc','#6699cc','#669999','#339966','#33ff66','#33ff00',
                       '#999900','#ffcc66','#330000','#ffcc99','#cc0033','#ff0099','#9900cc','#330066',
                       '#0066ff','#006699','#99cccc','#006633','#00ff66','#66ff00','#cccc00','#ffcc33',
                       '#663333','#ffffff','#ff0033','#ff33cc','#990099','#6600ff','#0033ff','#3399cc',
                       '#ccffff','#336633','#ccffcc','#99ff00','#cccc33','#cc9933','#996666','#cccccc',
                       '#ff9999','#ff00cc','#cc99cc','#6633ff','#3366ff','#0099cc','#33cccc','#669966',
                       '#ccff99','#66cc00','#333300','#996600','#cc9999','#999999','#cc3366','#ff66ff',
                       '#996699','#ccccff','#3366cc','#66ccff','#66cccc','#66cc66','#99ff66','#00ff00',
                       '#666600','#cc9900','#993333','#666666','#ffccff','#ff33ff','#663366','#9999ff',
                       '#000066','#3399ff','#339999','#99ff99','#99ff33','#33cc00','#999933','#ff9900',
                       '#cc6666','#333333','#cc6699','#ff00ff','#660099','#9999cc','#000033','#003399',
                       '#336666','#66ff66','#00ff33','#339900','#cccc66','#cc6600','#ffcccc','#993366',
                       '#cc0099','#9933cc','#6666cc','#0000ff','#0099ff','#006666','#339933','#33ff33',
                       '#99cc66','#666633','#993300','#ff3333','#660033','#990066','#660066','#6666ff',
                       '#000099','#33ccff','#003333','#99cc99','#00cc33','#669933','#999966','#cc6633',
                       '#cc3333','#cc3399','#cc66cc','#9900ff','#666699','#0033cc','#00ccff','#00ffcc',
                       '#66ff99','#33cc33','#99cc33','#cccc99','#663300','#ff6666','#ff99cc','#cc33cc',
                       '#9933ff','#333366','#0000cc','#99ffff','#33ffcc','#33ff99','#66ff33','#336600',
                       '#ffffcc','#ff9966','#660000','#ff66cc','#cc99ff','#9966cc','#333399','#336699',
                       '#66ffff','#33cc99','#33cc66','#009900','#669900','#ffff99','#ff6633','#990000',
                       '#ff99ff','#cc66ff','#330033','#330099','#0066cc','#33ffff','#00cc99','#00cc66',
                       '#66cc33','#99cc00','#ffff66','#ff9933','#cc0000','#ff6699','#cc33ff','#663399',
                       '#3300cc','#99ccff','#00ffff','#66ffcc','#66cc99','#006600','#ccff66','#ffff33',
                       '#ff6600','#ff0000','#cc0066','#993399','#6633cc','#3300ff','#6699ff','#00cccc',
                       '#99ffcc','#009966','#003300','#ccff33','#ffff00','#cc3300','#ff3300','#000000'];

var _tcGetColor = function(pos) {
    var idx = pos % _tcColorPattern.length;
    return _tcColorPattern[idx];
}

var _tcGetStringLength = function(str) {
    len = 0;
    for (var i = 0; i < str.length; i++) {
        if (str.charCodeAt(i) < 256) {
            len += 1;
        } else {
            len += 2;
        }
    }
    return len;
}

var _tcTFPad = function(v, len) {
    return ("000" + v).substr(-len);
}

var _tcTimestampFormat = function(value, BrushFromTo) {
    var differ = BrushFromTo[1] - BrushFromTo[0];
    var msec = value % 1000;  
    var dt = new Date(value);
    if (differ < 1000) { 
       // 1sec
       return "" + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2) + "." + _tcTFPad(msec, 3);
    } else if (differ < 60 * 1000) {
       // 1min
       return "" + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2) + "." + _tcTFPad(msec, 3);
    } else if (differ < 60 * 60 * 1000) {
       // 1hour
       return "" + _tcTFPad((dt.getMonth() + 1), 2) + "-" +  _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2) + ":" + _tcTFPad(dt.getSeconds(), 2);
    } else if (differ < 24 * 60 * 60 * 1000) {
       // 1day
       return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" +  _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2);
    } else if (differ < 7 * 24 * 60 * 60 * 1000) {
       // 1week
       return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" +  _tcTFPad(dt.getDate(), 2) + " " + _tcTFPad(dt.getHours(), 2) + ":" + _tcTFPad(dt.getMinutes(), 2);
    } else if (differ < 30 * 24 * 60 * 60 * 1000) {
       // 1month
       return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" +  _tcTFPad(dt.getDate(), 2); 
    } else {
       return "" + _tcTFPad(dt.getFullYear(), 4) + "-" + _tcTFPad((dt.getMonth() + 1), 2) + "-" +  _tcTFPad(dt.getDate(), 2); 
    }
}

var _tcElapsedTimeFormat = function(value, BrushFromTo) {
    var differ = BrushFromTo[1] - BrushFromTo[0];
    var dt = new Date(value);
    var week = Math.floor(value / (7 * 24 * 60 * 60 * 1000));
    value -= week * (7 * 24 * 60 * 60 * 1000);
    var day = Math.floor(value / (24 * 60 * 60 * 1000));
    value -= day * (24 * 60 * 60 * 1000);
    var hour = Math.floor(value / (60 * 60 * 1000));
    value -= hour * (60 * 60 * 1000);
    var min = Math.floor(value / (60 * 1000));
    value -= min * (60 * 1000);
    var sec = Math.floor(value / (1000));
    value -= sec * (1000);
    var msec = value;
    if (differ < 1000) { 
       // < 1sec
       return "" + msec + "ms";
    } else if (differ < 60 * 1000) {
       // < 1min
       return "" + sec + "s " + msec + "ms";
    } else if (differ < 60 * 60 * 1000) {
       // < 1hour
       return "" + min + "m " +  sec + "s ";
    } else if (differ < 24 * 60 * 60 * 1000) {
       // < 1day
       return "" + hour + "h " +  min + "m ";
    } else if (differ < 7 * 24 * 60 * 60 * 1000) {
       // < 1week
       return "" + day + "d " + hour + "h " +  min + "m ";
    } else  {
       // other
       return "" + week + "w " + day + "d " + hour + "h ";
    }
}

var _tcAdjustBlushValue = function(brushFrom, brushTo, start, end) {
    if (brushFrom == null ||
        brushTo == null) {
        brushFrom = start;
        brushTo = end;
    }
    if (brushFrom < start) {
        brushFrom = start;
    }
    if (brushTo > end) {
        brushTo = end;
    }
    if (brushTo == brushFrom) {
        brushFrom = start;
        brushTo = end;
    }
    return [brushFrom, brushTo];
}

var _tcGetBrushExtent = function(viewRange, start, end) {
    if (viewRange.from == null ||
        viewRange.to == null) {
        return [0, 0];
    } else {
        if (viewRange.from < start) {
            viewRange.from = start; 
        }
        if (viewRange.to > end) {
            viewRange.to = end;
        }
        return [viewRange.from, viewRange.to];
    }
}
var _tcGetCommonData = function(source) {
    var startDateMin = null;
    var endDateMax = null;
    var commonData = {}
    commonData.scrolls = [];
    commonData.tasks = [];
    commonData.containers = [ {cls: "scrollButtonsContainer"},
                              {cls: "optionsContainer" } ];
    commonData.datePickerContainersData = [ {cls: "datePickerContainer startDatePickerContainer", label: "start date :"},
                                            {cls: "datePickerContainer endDatePickerContainer", label: "end date :"} ]
    commonData.datePickersData = [ {span: "span.startDatePickerContainer", data: [{ cls: "startDatePicker" }] },
                                   {span: "span.endDatePickerContainer", data: [{ cls: "endDatePicker" }] } ]
    if (source.actors != null) {
        if (source.settings.drawActorsSummaryBarChart) {
            commonData.scrolls.push({target: "div.actorsSummaryBarChart", label: source.settings.actorsSummaryBarChart.label , cls: "tchartButton  ui-corner-all"});
        } else if (source.settings.drawActorsSwimlaneChart) {
            commonData.scrolls.push({target: "div.actorsSwimlaneChart", label: source.settings.actorsSwimlaneChart.label , cls: "tchartButton  ui-corner-all"});
        }
    }
    if (source.tasks != null) {
        commonData.scrolls.push({target: "div.tasksGanttChart", label: source.settings.tasksGanttChart.label, cls: "tchartButton  ui-corner-all"});
        commonData.scrolls.push({target: "div.tasksBarChart", label: source.settings.tasksBarChart.label, cls: "tchartButton  ui-corner-all"});
        var count = 0;
        for (var taskId in source.tasks) {
            if (startDateMin == null) {
                startDateMin = source.tasks[taskId].from;
            } else {
                if (source.tasks[taskId].from < startDateMin) {
                    startDateMin = source.tasks[taskId].from;
                }
            }
            if (endDateMax == null) {
                endDateMax = source.tasks[taskId].to;
            } else {
                if (source.tasks[taskId].to > endDateMax) {
                    endDateMax = source.tasks[taskId].to;
                }
            }
            if (source.settings.startDate != null && source.settings.startDate > source.tasks[taskId].from) {
                continue;
            }
            if (source.settings.endDate != null && (source.settings.endDate + 86400000) < source.tasks[taskId].to) {
                continue;
            }
            var color = _tcGetColor(count);
            source.tasks[taskId].color = color;
            var task = {
                taskId: taskId,
                name: source.tasks[taskId].name,
                from: source.tasks[taskId].from,
                to: source.tasks[taskId].to,
                elapse: source.tasks[taskId].to - source.tasks[taskId].from,
                clickEventArg: source.tasks[taskId].clickEventArg,
                color: source.tasks[taskId].color 
            };
            commonData.tasks.push(task);
            count += 1;
        }
    }
    if (source.settings.startDate == null) {
        source.settings.startDate = startDateMin;
    }
    if (source.settings.endDate == null) {
        source.settings.endDate = endDateMax;
    }
    commonData.tickWidth = source.settings.fontSize * 25 / 2;
    commonData.fromMin = d3.min(commonData.tasks, function(d){ return d.from });
    commonData.toMax = d3.max(commonData.tasks, function(d){ return d.to });
    commonData.elapseMax = d3.max(commonData.tasks, function(d){ return d.elapse });
    commonData.startDateMin = startDateMin;
    commonData.endDateMax = endDateMax;
    return commonData;
}

var _tcDrawCreateContainers = function(self, divSel, containerData) {
    var containers = d3.selectAll(self)
                       .selectAll(divSel)
                       .selectAll("div")
                       .data(containerData);
    containers.attr("class", function(d) { return d.cls })
    containers.enter()
                  .append("div")
                  .attr("class", function(d) { return d.cls })
    containers.exit().remove();
}

var _tcDrawCreateScrollButtons = function(self, divSel, scrollButtonsData) {
    var scrollButtons = d3.selectAll(self)
                          .selectAll(divSel)
                          .selectAll("div.scrollButtonsContainer")
                          .selectAll("button")
                          .data(scrollButtonsData);
    scrollButtons.attr("class", function(d) { return d.cls })
                 .text(function(d) { return d.label })
    scrollButtons.enter()
                     .append("button")
                     .attr("class", function(d) { return d.cls })
                     .text(function(d) { return d.label })
                     .on("click", function(d) {
                         $('html,body').animate(
                             { scrollTop: $(d.target).offset().top},
                             { duration: 100, easing: "swing" }
                         );
                     });
    scrollButtons.exit().remove();
    return scrollButtons;
}

var _tcDrawCreateSummaryButton = function(self, divSel, summaryButtonData, callback) {
    var summaryButton = d3.selectAll(self)
                          .selectAll(divSel)
                          .selectAll("div.optionsContainer")
                          .selectAll("button")
                          .data(summaryButtonData);
    summaryButton.attr("class", "tchartButton ui-corner-all")
                 .text(function(d) { return d.label })
                 .on("click", function(d) {
                     callback();
                 });
    summaryButton.enter()
                     .append("button")
                     .attr("class", "tchartButton ui-corner-all")
                     .text(function(d) { return d.label })
                     .on("click", function(d) {
                         callback();
                     });
    summaryButton.exit().remove();
    return summaryButton;
}

var _tcDrawCreatePrevNextInputs = function(self, divSel, startValue, stepValue, callbackAll, callbackPrev, callbackStart, callbackStep, callbackNext) {
    var prevNextContainers = d3.selectAll(self)
                               .selectAll(divSel)
                               .selectAll("div.optionsContainer")
                               .selectAll("span")
                               .data([{cls: "allContainer", label: ""},
                                      {cls: "prevContainer", label: ""},
                                      {cls: "startContainer", label: "start"},
                                      {cls: "stepContainer", label: "step"},
                                      {cls: "nextContainer", label: ""}]);
    prevNextContainers.enter()
                          .append("span")
                          .attr("class", function(d) { return d.cls })
                          .text(function(d) { return d.label })
    prevNextContainers.exit().remove();

    var allButton = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.allContainer")
                      .selectAll("button")
                      .data([{label: "all" }]);
    allButton.enter()
                 .append("button")
                 .attr("class", "tchartButton ui-corner-all")
                 .text(function(d) { return d.label })
                 .on("click", function(d) {
                     callbackAll();
                 });
    allButton.exit().remove();

    var prevButton = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.prevContainer")
                      .selectAll("button")
                      .data([{ label: "prev" }]);
    prevButton.enter()
                 .append("button")
                 .attr("class", "tchartButton ui-corner-all")
                 .text(function(d) { return d.label })
                 .on("click", function(d) {
                     callbackPrev();
                 });
    prevButton.exit().remove();

    var startInput = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.startContainer")
                      .selectAll("input")
                      .data([{cls: "startInput", type : "number"}]);
    startInput.enter()
                 .append("input")
                 .attr("class", function(d) { return d.cls })
                 .attr("type", function(d) { return d.type })
                 .on("change", function(d) {
                     callbackStart(this, d3.event);
                 });
    startInput.exit().remove();
    self.find("div.optionsContainer > span.startContainer > input.startInput").val(startValue + 1);

    var stepInput = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.stepContainer")
                      .selectAll("input")
                      .data([{cls: "stepInput", type : "number"}]);
    stepInput.enter()
                 .append("input")
                 .attr("class", function(d) { return d.cls })
                 .attr("type", function(d) { return d.type })
                 .on("change", function(d) {
                     callbackStep(this, d3.event);
                 });
    stepInput.exit().remove();
    self.find("div.optionsContainer > span.stepContainer > input.stepInput").val(stepValue);

    var nextButton = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.nextContainer")
                      .selectAll("button")
                      .data([{ label: "next" }]);
    nextButton.enter()
                 .append("button")
                 .attr("class", "tchartButton ui-corner-all")
                 .text(function(d) { return d.label })
                 .on("click", function(d) {
                     callbackNext();
                 });
    nextButton.exit().remove();

    return prevNextContainers;
}

var _tcDrawCreateHeadTailInputs = function(self, divSel, headValue, tailValue, callbackAll, callbackHead, callbackTail) {
    var headTailContainers = d3.selectAll(self)
                               .selectAll(divSel)
                               .selectAll("div.optionsContainer")
                               .selectAll("span")
                               .data([{cls: "allContainer", label: ""},
                                      {cls: "headContainer", label: "head"},
                                      {cls: "tailContainer", label: "tail"}]);
    headTailContainers.enter()
                          .append("span")
                          .attr("class", function(d) { return d.cls })
                          .text(function(d) { return d.label })
    headTailContainers.exit().remove();

    var allButton = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.allContainer")
                      .selectAll("button")
                      .data([{ label: "all" }]);
    allButton.enter()
                 .append("button")
                 .attr("class", "tchartButton ui-corner-all")
                 .text(function(d) { return d.label })
                 .on("click", function(d) {
                     callbackAll();
                 });
    allButton.exit().remove();

    var headInput = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.headContainer")
                      .selectAll("input")
                      .data([{cls: "headInput", type : "number"}]);
    headInput.enter()
                 .append("input")
                 .attr("class", function(d) { return d.cls })
                 .attr("type", function(d) { return d.type })
                 .on("change", function(d) {
                     callbackHead(this, d3.event);
                 });
    headInput.exit().remove();
    self.find("div.optionsContainer > span.headContainer > input.headInput").val(headValue);

    var tailInput = d3.selectAll(self)
                      .selectAll(divSel)
                      .selectAll("div.optionsContainer")
                      .selectAll("span.tailContainer")
                      .selectAll("input")
                      .data([{cls: "tailInput", type : "number"}]);
    tailInput.enter()
                 .append("input")
                 .attr("class", function(d) { return d.cls })
                 .attr("type", function(d) { return d.type })
                 .on("change", function(d) {
                     callbackTail(this, d3.event);
                 });
    tailInput.exit().remove();
    self.find("div.optionsContainer > span.tailContainer > input.tailInput").val(tailValue);

    return headTailContainers;
}

var _tcDrawCreateTopSvg = function(self, divSel, topSvgData) {
    var topSvg = d3.selectAll(self)
                   .selectAll(divSel)
                   .selectAll("svg")
                   .data(topSvgData);
    topSvg.attr("class", function(d) { return d.cls })
          .attr("width", function(d) { return d.width })
          .attr("height", function(d) { return d.height })
          .attr("viewBox", function(d) { return d.viewBox });
    topSvg.enter()
          .append("svg")
          .attr("class", function(d) { return d.cls })
          .attr("width", function(d) { return d.width })
          .attr("height", function(d) { return d.height })
          .attr("viewBox", function(d) { return d.viewBox });
    topSvg.exit().remove();
    return topSvg;
}

var _tcDrawCreateSubSvgs = function(topSvg, svgSel, subSvgsData) {
    var subSvgs = topSvg.selectAll(svgSel)
                        .data(subSvgsData)
    subSvgs.attr("x", function(d) { return d.x })
           .attr("y", function(d) { return d.y })
           .attr("width", function(d) { return d.width })
           .attr("height", function(d) { return d.height })
           .attr("viewBox", function(d) { return d.viewBox });
    subSvgs.enter()
               .append("svg")
               .attr("class", function(d) { return d.cls })
               .attr("preserveAspectRatio", function(d) { return d.preserveAspectRatio})
               .attr("x", function(d) { return d.x })
               .attr("y", function(d) { return d.y })
               .attr("width", function(d) { return d.width })
               .attr("height", function(d) { return d.height })
               .attr("viewBox", function(d) { return d.viewBox});
    subSvgs.exit().remove();
    return subSvgs;
}

var _tcDrawCreateTasksRects = function(topSvg, subSvg, rectSel, tasksRectsData, source, onTaskClick) {
    var tasksRects = topSvg.selectAll(subSvg)
                           .selectAll(rectSel)
                           .data(tasksRectsData);
    tasksRects.attr("x", function(d) { return d.x; })
              .attr("y", function(d) { return d.y; })
              .attr("width", function(d) { return d.width; })
              .attr("height", function(d) { return d.height; })
              .attr("fill", function(d) { return d.color; });
    tasksRects.enter()
                  .append("rect")
                  .attr("x", function(d) { return d.x; })
                  .attr("y", function(d) { return d.y; })
                  .attr("rx", function(d) { return d.rx; })
                  .attr("ry", function(d) { return d.ry; })
                  .attr("width", function(d) { return d.width; })
                  .attr("height", function(d) { return d.height; })
                  .attr("class", function(d) { return d.cls; })
                  .attr("fill", function(d) { return d.color; })
                  .on("click", function(d) {
                       if (onTaskClick && d.taskId) {
                           onTaskClick(source.tasks[d.taskId].clickEventArg, this, d3.event);
                       }
                  });
    tasksRects.exit().remove();
    return tasksRects;
}

var _tcDrawCreateLines = function(topSvg, subSvg, lineSel, linesData) {
    var lines = topSvg.selectAll(subSvg)
                      .selectAll(lineSel)
                      .data(linesData);
    lines.attr("x1", function(d) { return d.x1 })
         .attr("y1", function(d) { return d.y1 })
         .attr("x2", function(d) { return d.x2 })
         .attr("y2", function(d) { return d.y2 });
    lines.enter()
             .append("line")
             .attr("x1", function(d) { return d.x1 })
             .attr("y1", function(d) { return d.y1 })
             .attr("x2", function(d) { return d.x2 })
             .attr("y2", function(d) { return d.y2 })
             .attr("class", function(d) { return d.cls })
    lines.exit().remove();
    return lines;
}

var _tcDrawCreateLabels = function(topSvg, subSvg, textSel, labelsData, fontSize) {
    var labels = topSvg.selectAll(subSvg)
                       .selectAll(textSel)
                       .data(labelsData);
    labels.text(function(d) {return d.label})
          .attr("x", function(d) { return d.x; })
          .attr("y", function(d) { return d.y; })
          .style("font-size", fontSize + "px");
    labels.enter()
              .append("text")
              .text(function(d) {return d.label})
              .attr("x", function(d) { return d.x; })
              .attr("y", function(d) { return d.y; })
              .attr("class", function(d){ return d.cls; })
              .style("font-size", fontSize + "px");
    labels.exit().remove();
    return labels;
}

var _tcDrawCreateAxis = function(topSvg, subSvg, axisSel, axisData, axisScales, fontSize) {
    var axis = topSvg.selectAll(subSvg)
                     .selectAll(axisSel)
                     .data(axisData);
    axis.attr("class", function(d){ return d.cls; })
        .attr("transform", function(d) { return d.trans; });
    axis.enter()
            .append("g")
            .attr("transform", function(d) { return  d.trans; })
            .attr("class", function(d){ return d.cls; });
    axis.exit().remove();
    for (var i = 0; i < axisScales.length; i++) {
        topSvg.selectAll(subSvg)
              .selectAll(axisScales[i].group)
              .call(axisScales[i].scale)
              .selectAll("text")
              .style("font-size", fontSize + "px")
              .style("text-anchor", "start");
    }
    return axis;
}

var _tcDrawCreateBrushRects = function(topSvg, subSvg, rectSel, brushRectsData) {
    var brushRects = topSvg.selectAll(subSvg)
                           .selectAll(rectSel)
                           .data(brushRectsData);
    brushRects.attr("x", function(d) { return d.x; })
              .attr("y", function(d) { return d.y; })
              .attr("width", function(d) { return d.width; })
              .attr("height", function(d) { return d.height; })
              .attr("fill", function(d) { return d.color; });
    brushRects.enter()
                  .append("rect")
                  .attr("x", function(d) { return d.x; })
                  .attr("y", function(d) { return d.y; })
                  .attr("rx", function(d) { return d.rx; })
                  .attr("ry", function(d) { return d.ry; })
                  .attr("width", function(d) { return d.width; })
                  .attr("height", function(d) { return d.height; })
                  .attr("class", function(d) { return d.cls; })
                  .attr("fill", function(d) { return d.color; });
    brushRects.exit().remove();
    return brushRects;
}

var _tcDrawCreateBrush = function(topSvg, subSvg, brushSel, brushData, brushScales) {
    var brush = topSvg.selectAll(subSvg)
                      .selectAll(brushSel)
                      .data(brushData)
    brush.attr("class", function(d){ return d.cls; })
    brush.enter()
             .append("g")
             .attr("class", function(d){ return d.cls; })
    brush.exit().remove();
    for (var i = 0; i < brushScales.length; i++) {
        if (brushScales[i].type == "x") {
            topSvg.selectAll(subSvg)
                  .selectAll(brushScales[i].group)
                  .call(brushScales[i].scale)
                  .selectAll("rect")
                      .attr("height", brushScales[i].height)
        }
    }
    return brush;
}

var _tcDrawActorsSummaryBarChart = function(self, source, onTaskClick, commonData) {
    if (source.actors == null || !source.settings.drawActorsSummaryBarChart) {
        return;
    }
    // get need param
    if (commonData == null) {
        commonData = _tcGetCommonData(source);
    }
    var maxNameLen = 0;
    for (actorId in source.actors) {
        var len = _tcGetStringLength(source.actors[actorId].name);
        if (maxNameLen < len) {
            maxNameLen = len;
        }
    }
    // create summary data
    var actors = [];
    var count = 0;
    var tasksMax = 0;
    for (actorId in source.actors) {
            var actor = {
                name: actorId,
                color: _tcGetColor(count),
                taskSize: source.actors[actorId].tasks.length,
                taskId: null,
                clickEventArg: null
            }
            if (tasksMax < source.actors[actorId].tasks.length) {
                    tasksMax = source.actors[actorId].tasks.length;
            }
            actors.push(actor);
            count += 1;
    }
    // sort
    var sortedActors =  d3.values(actors).sort(function(a, b){ return d3.descending(a.taskSize, b.taskSize); });
    // defines
    var brushEndCb = function() {
        var extent = d3.event.target.extent();
        source.settings.actorsSummaryBarChart.viewRange.from = extent[0];
        source.settings.actorsSummaryBarChart.viewRange.to = extent[1];
        _tcDrawActorsSummaryBarChart(self, source, onTaskClick, null);
    }
    var fontSize = source.settings.fontSize;
    var yPadding = 8;
    var xOffset = ((maxNameLen * fontSize)/1.8) + fontSize + yPadding;
    var axisHeight = 8 + fontSize + yPadding + fontSize + yPadding; 
    var yOffset = axisHeight;
    var brushHeight = source.settings.brushHeight + yPadding;
    var barMaxHeight = source.settings.actorsSummaryBarChart.barMaxHeight;
    var canvasHeight = barMaxHeight * sortedActors.length; 
    var canvasWidth = source.settings.width - xOffset;
    var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
    var svgWidth = xOffset + canvasWidth;
    var xmax = tasksMax;
    var brushFromTo = _tcAdjustBlushValue(source.settings.actorsSummaryBarChart.viewRange.from,
                                          source.settings.actorsSummaryBarChart.viewRange.to,
                                          0,
                                          xmax);
    var zoom = xmax / (brushFromTo[1] - brushFromTo[0]);
    if ((brushFromTo[1] - brushFromTo[0]) == 0) {
       zoom = 1;
    }

    var x = d3.scale.linear()
                    .domain([0, xmax])
                    .range([0, canvasWidth]);
    var axisX = d3.scale.linear()
                         .domain([0, xmax])
                         .range([0, canvasWidth * zoom]);
    var y = d3.scale.linear()
                    .domain([0, 1])
                    .range([0, barMaxHeight]);
    var brushY = d3.scale.linear()
                          .domain([0, sortedActors.length])
                          .range([0, brushHeight - yPadding]);
    var xAxisTop = d3.svg.axis()
                         .scale(axisX)
                         .orient("top")
                         .ticks((canvasWidth / commonData.tickWidth) * zoom)
                         .tickSize(8, 4, 2)
    var xAxisBottom = d3.svg.axis()
                            .scale(axisX)
                            .orient("bottom")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
    var xBrushScale = d3.svg.brush().x(x)
                                    .on("brushend", brushEndCb)
                                    .extent(_tcGetBrushExtent(source.settings.actorsSummaryBarChart.viewRange, 0, xmax));
    // convert data
    var topSvgData = [{cls: "actorsSummaryBarChartSvg",
                       width: svgWidth,
                       height: svgHeight,
                       viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
    var subSvgsData = [{cls: "actorsSummaryBarChartRectsSvg actorsSummaryBarChartSubSvg",
                        x: xOffset,
                        y: yOffset,
                        width: canvasWidth,
                        height: canvasHeight,
                        preserveAspectRatio: "none",
                        viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
                       {cls: "actorsSummaryBarChartAxisSvg actorsSummaryBarChartSubSvg",
                        x: xOffset,
                        y: 0,
                        preserveAspectRatio: "xMidYMid",
                        width: canvasWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset +canvasHeight + axisHeight) },
                       {cls: "actorsSummaryBarChartLinesSvg actorsSummaryBarChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "actorsSummaryBarChartLabelsSvg actorsSummaryBarChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "actorsSummaryBarChartBrushSvg actorsSummaryBarChartSubSvg",
                        x: xOffset,
                        y: yOffset + canvasHeight + axisHeight,
                        width: canvasWidth,
                        height: brushHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
    var axisData = [{trans: "translate(0, " + yOffset + ")" ,
                     cls: "actorsSummaryBarChartXAxisTop actorsSummaryBarChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "actorsSummaryBarChartXAxisBottom actorsSummaryBarChartAxis",
                     scale: "x"}];
    var axisScales = [{group: "g.actorsSummaryBarChartXAxisTop",
                       scale: xAxisTop},
                      {group: "g.actorsSummaryBarChartXAxisBottom",
                       scale: xAxisBottom}];
    var brushData = [{cls:"actorsSummaryBarChartXBrush actorsSummaryBarChartBrush"}];
    var brushScales = [{group: "g.actorsSummaryBarChartXBrush",
                        scale: xBrushScale,
                        type: "x",
                        height: brushHeight - yPadding}];
    var tasksRectsData = [];
    var linesData = [];
    var labelsData = [];
    var brushRectsData = [];
    brushRectsData.push({cls:"actorsSummaryBarChartBrushBackgroundRect actorsSummaryBarChartBrushRect",
                        x: 0,
                        y: 0,
                        ry: 0,
                        ry: 0,
                        width: canvasWidth,
                        height: brushHeight - yPadding,
                        fill: "" });
    for (var i = 0; i < sortedActors.length; i++) {
        linesData.push({ x1: xOffset,
                         y1: y(i) + yOffset,
                         x2: canvasWidth + xOffset,
                         y2: y(i) + yOffset,
                         cls: "actorsSummaryBarChartLaneLine actorsSummaryBarChartLine" });
        labelsData.push({ x: 0,
                          y: yOffset + y(i) + (barMaxHeight / 2) + (fontSize / 2),
                          label: sortedActors[i].name,
                          cls: "actorsSummaryBarChartLabel" });
        tasksRectsData.push({ x: x(0),
                              y: y(i) + (barMaxHeight/16),
                              rx: 6,
                              ry: 6,
                              width: x(sortedActors[i].taskSize) - x(0),
                              height: barMaxHeight - ((barMaxHeight/16) * 2),
                              taskId: null,
                              color: sortedActors[i].color,
                              cls: "actorsSummaryBarChartTaskRect" }); 
        brushRectsData.push({ x: x(0),
                              y: brushY(i),
                              rx: 3,
                              ry: 3,
                              width: x(sortedActors[i].taskSize) - x(0),
                              height: (brushHeight - yPadding) / sortedActors.length,
                              color: sortedActors[i].color,
                              cls: "actorsSummaryBarChartBrushTaskRect actorsSummaryBarChartBrushRect" }); 
    }
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
    linesData.push({ x1: canvasWidth + xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls:  "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: yOffset,
                     cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
    linesData.push({ x1: xOffset,
                     y1: canvasHeight + yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "actorsSummaryBarChartCanvasLine actorsSummaryBarChartLine" });
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yPadding + fontSize,
                      label: "(tasks)",
                      cls: "actorsSummaryBarChartLabel"});
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yOffset + canvasHeight + axisHeight - yPadding,
                      label: "(tasks)",
                      cls: "actorsSummaryBarChartLabel"});
    labelsData.push({ x: 0,
                      y: yOffset - yPadding,
                      label: "(actors)",
                      cls: "actorsSummaryBarChartLabel" });

    var containers = _tcDrawCreateContainers(self,
                                             "div.actorsSummaryBarChart",
                                             commonData.containers);
    var scrollButtons = _tcDrawCreateScrollButtons(self,
                                                   "div.actorsSummaryBarChart",
                                                   commonData.scrolls);
    var summaryButtonData = [{ label: "detail" }];
    var summaryButton = _tcDrawCreateSummaryButton(self,
                                                   "div.actorsSummaryBarChart",
                                                   summaryButtonData,
                                                   function() {
                                                       source.settings.drawActorsSummaryBarChart = false;
                                                       _tcDraw(self, source, onTaskClick);
                                                   });
    var topSvg = _tcDrawCreateTopSvg(self,
                                     "div.actorsSummaryBarChart",
                                     topSvgData);
    var subSvgs = _tcDrawCreateSubSvgs(topSvg,
                                       "svg.actorsSummaryBarChartSubSvg",
                                       subSvgsData);
    var tasksRects = _tcDrawCreateTasksRects(topSvg,
                                             "svg.actorsSummaryBarChartRectsSvg",
                                             "actorsSummaryBarChartTaskRect",
                                             tasksRectsData,
                                             source,
                                             null);
    var lines = _tcDrawCreateLines(topSvg,
                                   "svg.actorsSummaryBarChartLinesSvg",
                                   "line.actorsSummaryBarChartLine",
                                   linesData);
    var labels = _tcDrawCreateLabels(topSvg,
                                     "svg.actorsSummaryBarChartLabelsSvg",
                                     "text.actorsSummaryBarChartLabel",
                                     labelsData,
                                     fontSize);
    var axis = _tcDrawCreateAxis(topSvg,
                                 "svg.actorsSummaryBarChartAxisSvg",
                                 "g.actorsSummaryBarChartAxis",
                                 axisData,
                                 axisScales,
                                 fontSize);
    var brushRects = _tcDrawCreateBrushRects(topSvg,
                                              "svg.actorsSummaryBarChartBrushSvg",
                                              "rect.actorsSummaryBarChartBrushRect",
                                               brushRectsData);
    var brush = _tcDrawCreateBrush(topSvg,
                                   "svg.actorsSummaryBarChartBrushSvg",
                                   "g.actorsSummaryBarChartBrush",
                                   brushData,
                                   brushScales);
}

var _tcDrawActorsSwimlaneChart = function(self, source, onTaskClick, commonData) {
    if (source.actors == null || !source.settings.drawActorsSwimlaneChart) {
        return;
    }
    // get need param
    if (commonData == null) {
        commonData = _tcGetCommonData(source);
    }
    var maxNameLen = 0;
    for (actorId in source.actors) {
        var len = _tcGetStringLength(source.actors[actorId].name);
        if (maxNameLen < len) {
            maxNameLen = len;
        }
    }
    // defines
    var brushEndCb = function() {
        var extent = d3.event.target.extent();
        source.settings.actorsSwimlaneChart.viewRange.from = extent[0];
        source.settings.actorsSwimlaneChart.viewRange.to = extent[1];
        _tcDrawActorsSwimlaneChart(self, source, onTaskClick, null);
    }
    var fontSize = source.settings.fontSize;
    var yPadding = 8;
    var xOffset = ((maxNameLen * fontSize) / 1.8) + fontSize + yPadding;
    var axisHeight = 8 + ((fontSize + yPadding) * 2) + fontSize; 
    var yOffset = axisHeight;
    var brushHeight = source.settings.brushHeight + yPadding;
    var barMaxHeight = source.settings.actorsSwimlaneChart.barMaxHeight;
    var canvasHeight = barMaxHeight * commonData.tasks.length; 
    var canvasWidth = source.settings.width - xOffset;
    var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
    var svgWidth = xOffset + canvasWidth;
    var xmax = commonData.toMax;
    var startTime = source.settings.startTime;
    if (startTime == null) {
        startTime = commonData.fromMin;
    }
    var brushFromTo = _tcAdjustBlushValue(source.settings.actorsSwimlaneChart.viewRange.from,
                                          source.settings.actorsSwimlaneChart.viewRange.to,
                                          startTime,
                                          xmax);
    var zoom = (xmax - startTime) / (brushFromTo[1] - brushFromTo[0]);
    if ((brushFromTo[1] - brushFromTo[0]) == 0) {
       zoom = 1;
    }
    var x = d3.scale.linear()
                    .domain([startTime, xmax])
                    .range([0, canvasWidth]);
    var axisX = d3.scale.linear()
                         .domain([startTime, xmax])
                         .range([0, canvasWidth * zoom]);
    var axisXRel = d3.scale.linear()
                           .domain([0, xmax - startTime])
                           .range([0, canvasWidth * zoom]);
    var y = d3.scale.linear()
                    .domain([0, 1])
                    .range([0, barMaxHeight]);
    var brushY = d3.scale.linear()
                          .domain([0, commonData.tasks.length])
                          .range([0, brushHeight - yPadding]);
    var xAxisTop = d3.svg.axis()
                         .scale(axisX)
                         .orient("top")
                         .ticks((canvasWidth / commonData.tickWidth) * zoom)
                         .tickSize(8, 4, 2)
                         .tickPadding(fontSize + 3)
                         .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
    var xRelAxisTop = d3.svg.axis()
                            .scale(axisXRel)
                            .orient("top")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
                            .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xAxisBottom = d3.svg.axis()
                            .scale(axisX)
                            .orient("bottom")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
                            .tickPadding(fontSize + 3)
                            .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
    var xRelAxisBottom = d3.svg.axis()
                               .scale(axisXRel)
                               .orient("bottom")
                               .ticks((canvasWidth / commonData.tickWidth) * zoom)
                               .tickSize(8, 4, 2)
                               .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xBrushScale = d3.svg.brush().x(x)
                                    .on("brushend", brushEndCb)
                                    .extent(_tcGetBrushExtent(source.settings.actorsSwimlaneChart.viewRange, startTime, xmax));
    // convert data
    var topSvgData = [{cls: "actorsSwimlaneChartSvg",
                       width: svgWidth,
                       height: svgHeight,
                       viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
    var subSvgsData = [{cls: "actorsSwimlaneChartRectsSvg actorsSwimlaneChartSubSvg",
                        x: xOffset,
                        y: yOffset,
                        width: canvasWidth,
                        height: canvasHeight,
                        preserveAspectRatio: "none",
                        viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
                       {cls: "actorsSwimlaneChartAxisSvg actorsSwimlaneChartSubSvg",
                        x: xOffset,
                        y: 0,
                        preserveAspectRatio: "xMidYMid",
                        width: canvasWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "actorsSwimlaneChartLinesSvg actorsSwimlaneChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "actorsSwimlaneChartLabelsSvg actorsSwimlaneChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "actorsSwimlaneChartBrushSvg actorsSwimlaneChartSubSvg",
                        x: xOffset,
                        y: yOffset + canvasHeight + axisHeight,
                        width: canvasWidth,
                        height: brushHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
    var axisData = [{trans: "translate(0, " +  yOffset + ")" ,
                     cls: "actorsSwimlaneChartXAxisTop actorsSwimlaneChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " +  yOffset + ")" ,
                     cls: "actorsSwimlaneChartXRelAxisTop actorsSwimlaneChartRelAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "actorsSwimlaneChartXAxisBottom actorsSwimlaneChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "actorsSwimlaneChartXRelAxisBottom actorsSwimlaneChartRelAxis",
                     scale: "x"}];
    var axisScales = [{group: "g.actorsSwimlaneChartXAxisTop",
                       scale: xAxisTop},
                      {group: "g.actorsSwimlaneChartXRelAxisTop",
                       scale: xRelAxisTop},
                      {group: "g.actorsSwimlaneChartXAxisBottom",
                       scale: xAxisBottom},
                      {group: "g.actorsSwimlaneChartXRelAxisBottom",
                       scale: xRelAxisBottom}];
    var brushData = [{cls:"actorsSwimlaneChartXBrush actorsSwimlaneChartBrush"}];
    var brushScales = [{group: "g.actorsSwimlaneChartXBrush",
                        scale: xBrushScale,
                        type: "x",
                        height: brushHeight - yPadding}];
    var tasksRectsData = [];
    var linesData = [];
    var labelsData = [];
    var brushRectsData = [];
    var totalTaskCount = 0;
    brushRectsData.push({cls:"actorsSwimlaneChartBrushBackgroundRect actorsSwimlaneChartBrushRect",
                        x: 0,
                        y: 0,
                        ry: 0,
                        ry: 0,
                        width: canvasWidth,
                        height: brushHeight - yPadding,
                        fill: "" });
    for (actorId in source.actors) {
        var laneMaxHeight = barMaxHeight * source.actors[actorId].tasks.length;
        linesData.push({ x1: xOffset,
                         y1: y(totalTaskCount) + yOffset,
                         x2: canvasWidth + xOffset,
                         y2: y(totalTaskCount) + yOffset,
                         cls: "actorsSwimlaneChartLaneLine actorsSwimlaneChartLine" });
        labelsData.push({ x: 0,
                          y: yOffset + y(totalTaskCount) + (laneMaxHeight / 2) + (fontSize / 2),
                          label: source.actors[actorId].name,
                          cls: "actorsSwimlaneChartLabel" });
        for (var j = 0; j < source.actors[actorId].tasks.length; j++) {
            var task = source.tasks[source.actors[actorId].tasks[j]];
            tasksRectsData.push({ x: x(task.from),
                                 y: y(totalTaskCount) + (barMaxHeight/16),
                                 rx: 6,
                                 ry: 6,
                                 width: x(task.to) - x(task.from),
                                 height: barMaxHeight - ((barMaxHeight/16) * 2),
                                 taskId: source.actors[actorId].tasks[j],
                                 color: task.color,
                                 cls: "actorsSwimlaneChartTaskRect" }); 
            brushRectsData.push({ x: x(task.from),
                                 y: brushY(totalTaskCount),
                                 rx: 3,
                                 ry: 3,
                                 width: x(task.to) - x(task.from),
                                 height: (brushHeight - yPadding) / commonData.tasks.length,
                                 color: task.color,
                                 cls: "actorsSwimlaneChartBrushTaskRect actorsSwimlaneChartBrushRect" }); 
            totalTaskCount += 1;
        }
    }
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
    linesData.push({ x1: canvasWidth + xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls:  "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: yOffset,
                     cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
    linesData.push({ x1: xOffset,
                     y1: canvasHeight + yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "actorsSwimlaneChartCanvasLine actorsSwimlaneChartLine" });
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yPadding + fontSize,
                      label: "(time)",
                      cls: "actorsSwimlaneChartLabel"});
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yOffset + canvasHeight + axisHeight - yPadding,
                      label: "(time)",
                      cls: "actorsSwimlaneChartLabel"});
    labelsData.push({ x: 0,
                      y: yOffset - yPadding,
                      label: "(actors)",
                      cls: "actorsSwimlaneChartLabel" });

    var containers = _tcDrawCreateContainers(self,
                                             "div.actorsSwimlaneChart",
                                             commonData.containers);
    var scrollButtons = _tcDrawCreateScrollButtons(self,
                                                   "div.actorsSwimlaneChart",
                                                   commonData.scrolls);
    var summaryButtonData = [{ label: "summary",
                               cls: "tchartSummaryButton  ui-corner-all"}];
    var summaryButton = _tcDrawCreateSummaryButton(self,
                                                   "div.actorsSwimlaneChart",
                                                   summaryButtonData,
                                                   function() {
                                                       source.settings.drawActorsSummaryBarChart = true;
                                                       _tcDraw(self, source, onTaskClick);
                                                   });
    var topSvg = _tcDrawCreateTopSvg(self,
                                     "div.actorsSwimlaneChart",
                                     topSvgData);
    var subSvgs = _tcDrawCreateSubSvgs(topSvg,
                                       "svg.actorsSwimlaneChartSubSvg",
                                       subSvgsData);
    var tasksRects = _tcDrawCreateTasksRects(topSvg,
                                             "svg.actorsSwimlaneChartRectsSvg",
                                             "actorsSwimlaneChartTaskRect",
                                             tasksRectsData,
                                             source,
                                             onTaskClick);
    var lines = _tcDrawCreateLines(topSvg,
                                   "svg.actorsSwimlaneChartLinesSvg",
                                   "line.actorsSwimlaneChartLine",
                                   linesData);
    var labels = _tcDrawCreateLabels(topSvg,
                                     "svg.actorsSwimlaneChartLabelsSvg",
                                     "text.actorsSwimlaneChartLabel",
                                     labelsData,
                                     fontSize);
    var axis = _tcDrawCreateAxis(topSvg,
                                 "svg.actorsSwimlaneChartAxisSvg",
                                 "g.actorsSwimlaneChartAxis",
                                 axisData,
                                 axisScales,
                                 fontSize);
    var brushRects = _tcDrawCreateBrushRects(topSvg,
                                              "svg.actorsSwimlaneChartBrushSvg",
                                              "rect.actorsSwimlaneChartBrushRect",
                                               brushRectsData);
    var brush = _tcDrawCreateBrush(topSvg,
                                   "svg.actorsSwimlaneChartBrushSvg",
                                   "g.actorsSwimlaneChartBrush",
                                   brushData,
                                   brushScales);
}

var _tcDrawTasksGanttChart = function(self, source, onTaskClick, commonData) {
    if (!source.settings.drawTasksGanttChart) {
        return;
    }
    // get need param
    if (commonData == null) {
        commonData = _tcGetCommonData(source);
    }
    var maxNameLen = 0;
    for (var i = 0; i < commonData.tasks.length; i++) {
        var len = _tcGetStringLength(commonData.tasks[i].name);
        if (maxNameLen < len) {
            maxNameLen = len;
        }
    }
    // sort
    var sortedTasks = d3.values(commonData.tasks).sort(function(a, b){ return d3.ascending(a.from, b.from); });
    var start = source.settings.tasksGanttChart.start;
    var end = start + source.settings.tasksGanttChart.step;
    if (start > sortedTasks.length - 1) {
        start = 0;
    }
    if (end > sortedTasks.length) {
        end = sortedTasks.length;
    }
    sortedTasks = sortedTasks.slice(start, end);
    // defines
    var brushEndCb = function() {
        var extent = d3.event.target.extent();
        source.settings.tasksGanttChart.viewRange.from = extent[0];
        source.settings.tasksGanttChart.viewRange.to = extent[1];
        _tcDrawTasksGanttChart(self, source, onTaskClick, null);
    }

    var fontSize = source.settings.fontSize;
    var yPadding = 8;
    var xOffset = ((maxNameLen * fontSize) / 1.8) + fontSize + yPadding;
    var axisHeight = 8 + ((fontSize + yPadding) * 2) + fontSize;
    var yOffset = axisHeight
    var brushHeight = source.settings.brushHeight + yPadding;
    var barMaxHeight = source.settings.tasksGanttChart.barMaxHeight;
    var laneMaxHeight = source.settings.tasksGanttChart.laneMaxHeight;
    var canvasHeight = laneMaxHeight * sortedTasks.length; 
    var canvasWidth = source.settings.width - xOffset;
    var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
    var svgWidth = xOffset + canvasWidth;
    var xmax = commonData.toMax;
    var startTime = source.settings.startTime;
    if (startTime == null) {
        startTime = commonData.fromMin;
    }
    var brushFromTo = _tcAdjustBlushValue(source.settings.tasksGanttChart.viewRange.from,
                                          source.settings.tasksGanttChart.viewRange.to,
                                          startTime,
                                          xmax);
    var zoom = (xmax - startTime) / (brushFromTo[1] - brushFromTo[0]);
    if ((brushFromTo[1] - brushFromTo[0]) == 0) {
       zoom = 1;
    }
    var x = d3.scale.linear()
                    .domain([startTime, xmax])
                    .range([0, canvasWidth]);
    var axisX = d3.scale.linear()
                        .domain([startTime, xmax])
                        .range([0, canvasWidth * zoom]);
    var axisXRel = d3.scale.linear()
                           .domain([0, xmax - startTime])
                           .range([0, canvasWidth * zoom]);
    var y = d3.scale.linear()
                    .domain([0, 1])
                    .range([0, laneMaxHeight]);
    var brushY = d3.scale.linear()
                          .domain([0, sortedTasks.length])
                          .range([0, brushHeight - yPadding]);
    var xAxisTop = d3.svg.axis()
                         .scale(axisX)
                         .orient("top")
                         .ticks((canvasWidth / commonData.tickWidth) * zoom)
                         .tickSize(8, 4, 2)
                         .tickPadding(fontSize + 3)
                         .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
    var xRelAxisTop = d3.svg.axis()
                            .scale(axisXRel)
                            .orient("top")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
                            .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xAxisBottom = d3.svg.axis()
                            .scale(axisX)
                            .orient("bottom")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
                            .tickPadding(fontSize + 3)
                            .tickFormat(function(d) { return _tcTimestampFormat(d, brushFromTo); })
    var xRelAxisBottom = d3.svg.axis()
                               .scale(axisXRel)
                               .orient("bottom")
                               .ticks((canvasWidth / commonData.tickWidth) * zoom)
                               .tickSize(8, 4, 2)
                               .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xBrushScale = d3.svg.brush().x(x)
                                    .on("brushend", brushEndCb)
                                    .extent(_tcGetBrushExtent(source.settings.tasksGanttChart.viewRange, startTime, xmax));
    // convert data
    var topSvgData = [{cls: "tasksGanttChartSvg",
                       width: svgWidth,
                       height: svgHeight,
                       viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
    var subSvgsData = [{cls: "tasksGanttChartRectsSvg tasksGanttChartSubSvg",
                        x: xOffset,
                        y: yOffset,
                        width: canvasWidth,
                        height: canvasHeight,
                        preserveAspectRatio: "none",
                        viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
                       {cls: "tasksGanttChartAxisSvg tasksGanttChartSubSvg",
                        x: xOffset,
                        y: 0,
                        preserveAspectRatio: "xMidYMid",
                        width: canvasWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "tasksGanttChartLinesSvg tasksGanttChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "tasksGanttChartLabelsSvg tasksGanttChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "tasksGanttChartBrushSvg tasksGanttChartSubSvg",
                        x: xOffset,
                        y: yOffset + canvasHeight + axisHeight,
                        width: canvasWidth,
                        height: brushHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
    var axisData = [{trans: "translate(0, " + (yOffset) + ")" ,
                     cls: "tasksGanttChartXAxisTop tasksGanttChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset) + ")" ,
                     cls: "tasksGanttChartXRelAxisTop tasksGanttChartRelAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "tasksGanttChartXAxisBottom tasksGanttChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "tasksGanttChartXRelAxisBottom tasksGanttChartRelAxis",
                     scale: "x"}];
    var axisScales = [{group: "g.tasksGanttChartXAxisTop",
                       scale: xAxisTop},
                      {group: "g.tasksGanttChartXRelAxisTop",
                       scale: xRelAxisTop},
                      {group: "g.tasksGanttChartXAxisBottom",
                       scale: xAxisBottom},
                      {group: "g.tasksGanttChartXRelAxisBottom",
                       scale: xRelAxisBottom}];
    var brushData = [{cls:"tasksGanttChartXBrush tasksGanttChartBrush"}];
    var brushScales = [{group: "g.tasksGanttChartXBrush",
                        scale: xBrushScale,
                        type: "x",
                        height: brushHeight - yPadding}];
    var tasksRectsData = [];
    var linesData = [];
    var labelsData = [];
    var brushRectsData = [];
    brushRectsData.push({cls:"tasksGanttChartBrushBackgroundRect tasksGanttChartBrushRect",
                        x: 0,
                        y: 0,
                        ry: 0,
                        ry: 0,
                        width: canvasWidth,
                        height: brushHeight - yPadding,
                        fill: "" });
    for (var i = 0; i < sortedTasks.length; i++) {
        linesData.push({ x1: xOffset,
                         y1: y(i) + yOffset,
                         x2: canvasWidth + xOffset,
                         y2: y(i) + yOffset,
                         cls: "tasksGanttChartLaneLine tasksGanttChartLine" });
        labelsData.push({ x: 0,
                          y: yOffset + y(i) + (laneMaxHeight / 2) + (fontSize / 2),
                          label: sortedTasks[i].name,
                          cls: "tasksGanttChartLabel" });
        tasksRectsData.push({ x: x(sortedTasks[i].from),
                              y: y(i) + ((laneMaxHeight - barMaxHeight) / 2),
                              rx: 6,
                              ry: 6,
                              width: x(sortedTasks[i].to) - x(sortedTasks[i].from),
                              height: barMaxHeight - ((barMaxHeight/16) * 2),
                              taskId: sortedTasks[i].taskId,
                              color: sortedTasks[i].color,
                              cls: "tasksGanttChartTaskRect" }); 
        brushRectsData.push({ x: x(sortedTasks[i].from),
                              y: brushY(i),
                              rx: 3,
                              ry: 3,
                              width: x(sortedTasks[i].to) - x(sortedTasks[i].from),
                              height: (brushHeight - yPadding) / sortedTasks.length,
                              color: sortedTasks[i].color,
                              cls: "tasksGanttChartBrushTaskRect tasksGanttChartBrushRect" }); 
    }
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
    linesData.push({ x1: canvasWidth + xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls:  "tasksGanttChartCanvasLine tasksGanttChartLine" });
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: yOffset,
                     cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
    linesData.push({ x1: xOffset,
                     y1: canvasHeight + yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "tasksGanttChartCanvasLine tasksGanttChartLine" });
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yPadding + fontSize,
                      label: "(time)",
                      cls: "tasksGanttChartLabel"});
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yOffset + canvasHeight + axisHeight - yPadding,
                      label: "(time)",
                      cls: "tasksGanttChartLabel"});
    labelsData.push({ x: 0,
                      y: yOffset - yPadding,
                      label: "(tasks)",
                      cls: "tasksGanttChartLabel" });

    var containers = _tcDrawCreateContainers(self,
                                             "div.tasksGanttChart",
                                             commonData.containers);
    var scrollButtons = _tcDrawCreateScrollButtons(self,
                                                   "div.tasksGanttChart",
                                                   commonData.scrolls);
    var prevNextInputs = _tcDrawCreatePrevNextInputs(self,
                                                       "div.tasksGanttChart",
                                                       source.settings.tasksGanttChart.start,
                                                       source.settings.tasksGanttChart.step,
                                                       function() {
                                                           source.settings.tasksGanttChart.start = 0; 
                                                           source.settings.tasksGanttChart.step = commonData.tasks.length; 
                                                           _tcDrawTasksGanttChart(self, source, onTaskClick, null);
                                                       },
                                                       function() {
                                                           source.settings.tasksGanttChart.start -= source.settings.tasksGanttChart.step;
                                                           if (source.settings.tasksGanttChart.start < 0) {
                                                               source.settings.tasksGanttChart.start = 0;
                                                           }
                                                           _tcDrawTasksGanttChart(self, source, onTaskClick, null);
                                                       },
                                                       function(target, event) {
                                                           var start = parseInt(event.target.value) - 1;
                                                           if (typeof start === "number" && !isNaN(start) && start >= 0) {
                                                               source.settings.tasksGanttChart.start = start;
                                                           }
                                                           _tcDrawTasksGanttChart(self, source, onTaskClick, null);
                                                       },
                                                       function(target, event) {
                                                           var step = parseInt(event.target.value);
                                                           if (typeof step === "number" && !isNaN(step) && step >= 0) {
                                                               source.settings.tasksGanttChart.step = step;
                                                           }
                                                           _tcDrawTasksGanttChart(self, source, onTaskClick, null);
                                                       },
                                                       function() {
                                                           if (source.settings.tasksGanttChart.start + source.settings.tasksGanttChart.step <= commonData.tasks.length - 1) {
                                                               source.settings.tasksGanttChart.start += source.settings.tasksGanttChart.step;
                                                           }
                                                           _tcDrawTasksGanttChart(self, source, onTaskClick, null);
                                                       });
    var topSvg = _tcDrawCreateTopSvg(self,
                                     "div.tasksGanttChart",
                                     topSvgData);
    var subSvgs = _tcDrawCreateSubSvgs(topSvg,
                                       "svg.tasksGanttChartSubSvg",
                                       subSvgsData);
    var tasksRects = _tcDrawCreateTasksRects(topSvg,
                                             "svg.tasksGanttChartRectsSvg",
                                             "tasksGanttChartTaskRect",
                                             tasksRectsData,
                                             source,
                                             onTaskClick);
    var lines = _tcDrawCreateLines(topSvg,
                                   "svg.tasksGanttChartLinesSvg",
                                   "line.tasksGanttChartLine",
                                   linesData);
    var labels = _tcDrawCreateLabels(topSvg,
                                     "svg.tasksGanttChartLabelsSvg",
                                     "text.tasksGanttChartLabel",
                                     labelsData,
                                     fontSize);
    var axis = _tcDrawCreateAxis(topSvg,
                                 "svg.tasksGanttChartAxisSvg",
                                 "g.tasksGanttChartAxis",
                                 axisData,
                                 axisScales,
                                 fontSize);
    var brushRects = _tcDrawCreateBrushRects(topSvg,
                                              "svg.tasksGanttChartBrushSvg",
                                              "rect.tasksGanttChartBrushRect",
                                               brushRectsData);
    var brush = _tcDrawCreateBrush(topSvg,
                                   "svg.tasksGanttChartBrushSvg",
                                   "g.tasksGanttChartBrush",
                                   brushData,
                                   brushScales);
}

var _tcDrawTasksBarChart = function(self, source, onTaskClick, commonData) {
    if (!source.settings.drawTasksBarChart) {
        return;
    }
    // get need param
    if (commonData == null) {
        commonData = _tcGetCommonData(source);
    }
    var maxNameLen = 0;
    for (var i = 0; i < commonData.tasks.length; i++) {
        var len = _tcGetStringLength(commonData.tasks[i].name);
        if (maxNameLen < len) {
            maxNameLen = len;
        }
    }
    // sort
    var sortedTasks =  d3.values(commonData.tasks).sort(function(a, b){ return d3.descending(a.elapse, b.elapse); });
    var head = source.settings.tasksBarChart.head;
    var tail = source.settings.tasksBarChart.tail;
    var snipdot = {
        taskId: null,
        name: " .",
        elapse: 0, 
        taskId: null,
        clickEventArg: null,
        color: "#000000"
    };
    var snip = {
        taskId: null,
        name: "(snip)",
        elapse: 0, 
        taskId: null,
        clickEventArg: null,
        color: "#000000"
    };
    if (sortedTasks.length > head + tail) {
            sortedTasks.splice(head, sortedTasks.length - (head + tail), snipdot, snipdot, snipdot, snip, snipdot, snipdot, snipdot);
    }
    // defines
    var brushEndCb = function() {
        var extent = d3.event.target.extent();
        source.settings.tasksBarChart.viewRange.from = extent[0];
        source.settings.tasksBarChart.viewRange.to = extent[1];
        _tcDrawTasksBarChart(self, source, onTaskClick, null);
    }
    var fontSize = source.settings.fontSize;
    var yPadding = 8;
    var xOffset = ((maxNameLen * fontSize)/1.8) + fontSize + yPadding;
    var axisHeight = 8 + fontSize + yPadding + fontSize + yPadding; 
    var yOffset = axisHeight;
    var brushHeight = source.settings.brushHeight + yPadding;
    var barMaxHeight = source.settings.tasksBarChart.barMaxHeight;
    var canvasHeight = barMaxHeight * sortedTasks.length; 
    var canvasWidth = source.settings.width - xOffset;
    var svgHeight = yOffset + canvasHeight + axisHeight + brushHeight + 20;
    var svgWidth = xOffset + canvasWidth;
    var xmax = commonData.elapseMax
    var brushFromTo = _tcAdjustBlushValue(source.settings.tasksBarChart.viewRange.from,
                                          source.settings.tasksBarChart.viewRange.to,
                                          0,
                                          xmax);
    var zoom = xmax / (brushFromTo[1] - brushFromTo[0]);
    if ((brushFromTo[1] - brushFromTo[0]) == 0) {
       zoom = 1;
    }

    var x = d3.scale.linear()
                    .domain([0, xmax])
                    .range([0, canvasWidth]);
    var axisX = d3.scale.linear()
                         .domain([0, xmax])
                         .range([0, canvasWidth * zoom]);
    var y = d3.scale.linear()
                    .domain([0, 1])
                    .range([0, barMaxHeight]);
    var brushY = d3.scale.linear()
                          .domain([0, sortedTasks.length])
                          .range([0, brushHeight - yPadding]);
    var xAxisTop = d3.svg.axis()
                         .scale(axisX)
                         .orient("top")
                         .ticks((canvasWidth / commonData.tickWidth) * zoom)
                         .tickSize(8, 4, 2)
                         .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xAxisBottom = d3.svg.axis()
                            .scale(axisX)
                            .orient("bottom")
                            .ticks((canvasWidth / commonData.tickWidth) * zoom)
                            .tickSize(8, 4, 2)
                            .tickFormat(function(d) { return _tcElapsedTimeFormat(d, brushFromTo); })
    var xBrushScale = d3.svg.brush().x(x)
                                    .on("brushend", brushEndCb)
                                    .extent(_tcGetBrushExtent(source.settings.tasksBarChart.viewRange, 0, xmax));
    // convert data
    var topSvgData = [{cls: "tasksBarChartSvg",
                       width: svgWidth,
                       height: svgHeight,
                       viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + svgHeight }];
    var subSvgsData = [{cls: "tasksBarChartRectsSvg tasksBarChartSubSvg",
                        x: xOffset,
                        y: yOffset,
                        width: canvasWidth,
                        height: canvasHeight,
                        preserveAspectRatio: "none",
                        viewBox: "" + x(brushFromTo[0]) + " " + 0 + " " + (canvasWidth / zoom) + " " + canvasHeight },
                       {cls: "tasksBarChartAxisSvg tasksBarChartSubSvg",
                        x: xOffset,
                        y: 0,
                        preserveAspectRatio: "xMidYMid",
                        width: canvasWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        viewBox: "" + axisX(brushFromTo[0]) + " " + 0 + " " + canvasWidth + " " + (yOffset +canvasHeight + axisHeight) },
                       {cls: "tasksBarChartLinesSvg tasksBarChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "tasksBarChartLabelsSvg tasksBarChartSubSvg",
                        x: 0,
                        y: 0,
                        width: svgWidth,
                        height: yOffset + canvasHeight + axisHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + svgWidth + " " + (yOffset + canvasHeight + axisHeight) },
                       {cls: "tasksBarChartBrushSvg tasksBarChartSubSvg",
                        x: xOffset,
                        y: yOffset + canvasHeight + axisHeight,
                        width: canvasWidth,
                        height: brushHeight,
                        preserveAspectRatio: "xMidYMid",
                        viewBox: "" + 0 + " " + 0 + " " + canvasWidth + " " + brushHeight }];
    var axisData = [{trans: "translate(0, " + yOffset + ")" ,
                     cls: "tasksBarChartXAxisTop tasksBarChartAxis",
                     scale: "x"},
                    {trans: "translate(0, " + (yOffset + canvasHeight) + ")" ,
                     cls: "tasksBarChartXAxisBottom tasksBarChartAxis",
                     scale: "x"}];
    var axisScales = [{group: "g.tasksBarChartXAxisTop",
                       scale: xAxisTop},
                      {group: "g.tasksBarChartXAxisBottom",
                       scale: xAxisBottom}];
    var brushData = [{cls:"tasksBarChartXBrush tasksBarChartBrush"}];
    var brushScales = [{group: "g.tasksBarChartXBrush",
                        scale: xBrushScale,
                        type: "x",
                        height: brushHeight - yPadding}];
    var tasksRectsData = [];
    var linesData = [];
    var labelsData = [];
    var brushRectsData = [];
    brushRectsData.push({cls:"tasksBarChartBrushBackgroundRect tasksBarChartBrushRect",
                        x: 0,
                        y: 0,
                        ry: 0,
                        ry: 0,
                        width: canvasWidth,
                        height: brushHeight - yPadding,
                        fill: "" });
    for (var i = 0; i < sortedTasks.length; i++) {
        linesData.push({ x1: xOffset,
                         y1: y(i) + yOffset,
                         x2: canvasWidth + xOffset,
                         y2: y(i) + yOffset,
                         cls: "tasksBarChartLaneLine tasksBarChartLine" });
        labelsData.push({ x: 0,
                          y: yOffset + y(i) + (barMaxHeight / 2) + (fontSize / 2),
                          label: sortedTasks[i].name,
                          cls: "tasksBarChartLabel" });
        tasksRectsData.push({ x: x(0),
                              y: y(i) + (barMaxHeight/16),
                              rx: 6,
                              ry: 6,
                              width: x(sortedTasks[i].elapse) - x(0),
                              height: barMaxHeight - ((barMaxHeight/16) * 2),
                              taskId: sortedTasks[i].taskId,
                              color: sortedTasks[i].color,
                              cls: "tasksBarChartTaskRect" }); 
        brushRectsData.push({ x: x(0),
                              y: brushY(i),
                              rx: 3,
                              ry: 3,
                              width: x(sortedTasks[i].elapse) - x(0),
                              height: (brushHeight - yPadding) / sortedTasks.length,
                              color: sortedTasks[i].color,
                              cls: "tasksBarChartBrushTaskRect tasksBarChartBrushRect" }); 
    }
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "tasksBarChartCanvasLine tasksBarChartLine" });
    linesData.push({ x1: canvasWidth + xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls:  "tasksBarChartCanvasLine tasksBarChartLine" });
    linesData.push({ x1: xOffset,
                     y1: yOffset,
                     x2: canvasWidth + xOffset,
                     y2: yOffset,
                     cls: "tasksBarChartCanvasLine tasksBarChartLine" });
    linesData.push({ x1: xOffset,
                     y1: canvasHeight + yOffset,
                     x2: canvasWidth + xOffset,
                     y2: canvasHeight + yOffset,
                     cls: "tasksBarChartCanvasLine tasksBarChartLine" });
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yPadding + fontSize,
                      label: "(time)",
                      cls: "tasksBarChartLabel"});
    labelsData.push({ x: xOffset + canvasWidth - (fontSize * 4),
                      y: yOffset + canvasHeight + axisHeight - yPadding,
                      label: "(time)",
                      cls: "tasksBarChartLabel"});
    labelsData.push({ x: 0,
                      y: yOffset - yPadding,
                      label: "(tasks)",
                      cls: "tasksBarChartLabel" });

    var containers = _tcDrawCreateContainers(self,
                                             "div.tasksBarChart",
                                             commonData.containers);
    var scrollButtons = _tcDrawCreateScrollButtons(self,
                                                   "div.tasksBarChart",
                                                   commonData.scrolls);
    var headTailInputs = _tcDrawCreateHeadTailInputs(self,
                                                     "div.tasksBarChart",
                                                     source.settings.tasksBarChart.head,
                                                     source.settings.tasksBarChart.tail,
                                                     function() {
                                                         source.settings.tasksBarChart.head = commonData.tasks.length;
                                                         source.settings.tasksBarChart.tail = 0;
                                                         _tcDrawTasksBarChart(self, source, onTaskClick, null);
                                                     },
                                                     function(target, event) {
                                                         var head = parseInt(event.target.value);
                                                         if (typeof head === "number" && !isNaN(head) && head >= 0) {
                                                             source.settings.tasksBarChart.head = head;
                                                         }
                                                         _tcDrawTasksBarChart(self, source, onTaskClick, null);
                                                     },
                                                     function(target, event) {
                                                         var tail = parseInt(event.target.value);
                                                         if (typeof tail === "number" && !isNaN(tail) && tail >= 0) {
                                                             source.settings.tasksBarChart.tail = tail;
                                                         }
                                                         _tcDrawTasksBarChart(self, source, onTaskClick, null);
                                                     });
    var topSvg = _tcDrawCreateTopSvg(self,
                                     "div.tasksBarChart",
                                     topSvgData);
    var subSvgs = _tcDrawCreateSubSvgs(topSvg,
                                       "svg.tasksBarChartSubSvg",
                                       subSvgsData);
    var tasksRects = _tcDrawCreateTasksRects(topSvg,
                                             "svg.tasksBarChartRectsSvg",
                                             "tasksBarChartTaskRect",
                                             tasksRectsData,
                                             source,
                                             onTaskClick);
    var lines = _tcDrawCreateLines(topSvg,
                                   "svg.tasksBarChartLinesSvg",
                                   "line.tasksBarChartLine",
                                   linesData);
    var labels = _tcDrawCreateLabels(topSvg,
                                     "svg.tasksBarChartLabelsSvg",
                                     "text.tasksBarChartLabel",
                                     labelsData,
                                     fontSize);
    var axis = _tcDrawCreateAxis(topSvg,
                                 "svg.tasksBarChartAxisSvg",
                                 "g.tasksBarChartAxis",
                                 axisData,
                                 axisScales,
                                 fontSize);
    var brushRects = _tcDrawCreateBrushRects(topSvg,
                                              "svg.tasksBarChartBrushSvg",
                                              "rect.tasksBarChartBrushRect",
                                               brushRectsData);
    var brush = _tcDrawCreateBrush(topSvg,
                                   "svg.tasksBarChartBrushSvg",
                                   "g.tasksBarChartBrush",
                                   brushData,
                                   brushScales);
}

var _tcDraw = function(self, source, onTaskClick) {
    if (source.tasks == null) {
        return;
    }

    // getCommonData
    var commonData = _tcGetCommonData(source);

    // check tasks
    if (commonData.tasks.length == 0) {
        return;
    }

    // datepicket Containers
    var datePickerContainers = d3.selectAll(self)
                                 .selectAll("span.datePickerContainer")
                                 .data(commonData.datePickerContainersData);
    datePickerContainers.enter()
                            .append("span")
                            .text(function (d) { return d.label})
                            .attr("class", function(d) { return d.cls })
    datePickerContainers.exit().remove();

    // datePickers
    for (var i = 0; i < commonData.datePickersData.length; i++) {
        var datePicker = d3.selectAll(self)
                           .selectAll(commonData.datePickersData[i].span)
                           .selectAll("input")
                           .data(commonData.datePickersData[i].data)
        datePicker.enter()
                      .append("input")
                      .attr("type", "text")
                      .attr("class", function(d) { return d.cls });
        datePicker.exit().remove()
    }
    var startDatePicker = $(".startDatePicker").datepicker({ onSelect: function() {
                              source.settings.startDate = Date.parse($(this).val());
                              _tcDraw(self, source, onTaskClick);
                          }});
    var startDate = new Date(source.settings.startDate);
    startDatePicker.datepicker("option", "dateFormat", "yy-mm-dd")
    startDatePicker.datepicker("option", "minDate", new Date(commonData.startDateMin))
    startDatePicker.datepicker("option", "maxDate", new Date(commonData.endDateMax))
    startDatePicker.val(startDate.getFullYear() + "-" + _tcTFPad((startDate.getMonth() + 1), 2) + "-" + _tcTFPad(startDate.getDate(), 2))

    var endDatePicker = $(".endDatePicker").datepicker({ onSelect: function() {
                              source.settings.endDate = Date.parse($(this).val());
                              _tcDraw(self, source, onTaskClick);
                        }});
    var endDate = new Date(source.settings.endDate);
    endDatePicker.datepicker("option", "dateFormat", "yy-mm-dd")
    endDatePicker.datepicker("option", "minDate", new Date(commonData.startDateMin))
    endDatePicker.datepicker("option", "maxDate", new Date(commonData.endDateMax))
    endDatePicker.val(endDate.getFullYear() + "-" + _tcTFPad((endDate.getMonth() + 1), 2) + "-" + _tcTFPad(endDate.getDate(), 2))

    // create svg divs
    var containers = []
    if (source.actors != null) {
            if (source.settings.drawActorsSummaryBarChart) {
                containers.push("actorsSummaryBarChart chartContainer");
            } else if (source.settings.drawActorsSwimlaneChart){
                containers.push("actorsSwimlaneChart chartContainer");
            }
    }
    containers.push("tasksGanttChart chartContainer");
    containers.push("tasksBarChart chartContainer");

    var topDivs = d3.selectAll(self)
                    .selectAll("div.chartContainer")
                    .data(containers)
    topDivs.attr("class", function(d) { return d });
    topDivs.enter()
               .append("div")
               .attr("class", function(d) { return d });
    topDivs.exit().remove();

    // draw charts
    if (source.actors != null) {
            if (source.settings.drawActorsSummaryBarChart) {
                    _tcDrawActorsSummaryBarChart(self, source, onTaskClick, commonData);
            } else if (source.settings.drawActorsSwimlaneChart) {
                    _tcDrawActorsSwimlaneChart(self, source, onTaskClick, commonData);
            }
    }
    _tcDrawTasksGanttChart(self, source, onTaskClick, commonData);
    _tcDrawTasksBarChart(self, source, onTaskClick, commonData);
};

var _tcRemove = function(self, data) {
    d3.selectAll(self).selectAll("div")
          .data([])
          .exit()
          .remove();
};

var _tcDataUpdate = function(data, source) {
    source.settings.startDate = null;
    if ("settings" in source) {
        $.extend(true, data.source.settings, source.settings);
    }
    if ("actors" in source) {
        data.source.actors = source.actors;
    }
    if ("tasks" in source) {
        data.source.tasks = source.tasks;
    }
}

var _tcAjax = function(self, data) {
    $.ajax(data.ajaxParams).done(function(source) {
        _tcDataUpdate(data, source);
        _tcDraw(self, data.source, data.onTaskClick);
    }) 
}

var _tcAjaxTimer = function(self, data) {
    if (data.ajaxPending) {
        if (data.ajaxTimerId != null) {
            clearInterval(data.ajaxTimerId);
            data.ajaxTimerId = null;
        }
    } else {
        if (data.ajaxTimerId == null) {
            data.ajaxTimerId = setInterval(function(){_tcAjax(self, data)();}, data.ajaxInterval);
        }
        _tcAjax(self, data);
    }
}

var _tcDrawPrepare = function(self, data) {
    if (data.source.actors || data.source.tasks) {
        _tcDraw(self, data.source, data.onTaskClick);
    } else if (data.ajax != null && typeof data.ajax == "object" && typeof data.ajaxInterval == "number") {
        _tcAjaxTimer(self, data)
    } else if (data.ajax != null && typeof data.ajax == "object") {
        _tcAjax(self, data);
    }
}

var _tcRemovePrepare = function(self, data) {
    if (data.ajaxTimerId != null) {
        clearInterval(data.ajaxTimerId);
        data.ajaxTimerId = null;
    }
    _tcRemove(self, data.source);
}

var tchart = {
    init: function(options) {
        var data = this.data('tchart');
        if (!data) {
            this.data('tchart',
                $.extend(true, {
                    ajaxTimerId: null,
                    ajaxParams: null,
                    ajaxInterval: null,
                    ajaxPending: false,
                    onTaskClick: null,
                    source: {
                        settings : {
                            drawActorsSummaryBarChart: true,
                            drawActorsSwimlaneChart: true,
                            drawTasksGanttChart: true,
                            drawTasksBarChart: true,
                            fontSize: 12,
                            width: 500,
                            actorsSummaryBarChart : {
                                label: "actors summary bar chart",
                                barMaxHeight: 16,
                                viewRange: {
                                     from: null,
                                     to: null
                                }
                            },
                            actorsSwimlaneChart : {
                                label: "actors swimlane chart",
                                barMaxHeight:14,
                                viewRange: {
                                     from: null,
                                     to: null
                                }
                            },
                            tasksGanttChart : {
                                start: 0,
                                step: 50,
                                label: "tasks gantt chart",
                                barMaxHeight: 14,
                                laneMaxHeight:16,
                                viewRange: {
                                     from: null,
                                     to: null
                                }
                            },
                            tasksBarChart : {
                                head: 20,
                                tail: 20,
                                label: "tasks bar chart",
                                barMaxHeight: 16,
                                viewRange: {
                                     from: null,
                                     to: null
                                }
                            },
                            startTime: null,
                            brushHeight: 30,
                            startDate: null,
                            endDate: null
                        },
                        actors: null,
                        tasks: null
                    },
                }, options));
            data = this.data('tchart');
        }
        _tcDrawPrepare(this, data);
        return this;
    },
    update: function(source) {
        var data = this.data('tchart');
        if (!data) {
            return this;
        }
        _tcDataUpdate(data, source);
        _tcDraw(this, data.source, data.onTaskClick);
        return this;
    },
    remove: function() {
        var data = this.data('tchart');
        if (!data) {
            return this;
        }
        _tcRemovePrepare(this, data.source);
        return this;
    },
    pendingAjax: function(source) {
        var data = this.data('tchart');
        if (!data) {
            return this;
        }
        data.ajaxPending = true;
        _tcAjaxTimer(this, data);
        return this;
    },
    resumeAjax: function(source) {
        var data = this.data('tchart');
        if (!data) {
            return this;
        }
        data.ajaxResume = true;
        _tcAjaxTimer(this, data);
        return this;
    }
}

$.fn.tchart = function(method) {
    if (tchart[method]) {
        return tchart[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
        return tchart.init.apply(this, arguments);
    } else {
        $.error('Method ' +  method + ' does not exist on jQuery.tchart');
    }  
    return this;
}

})(jQuery);

////////////////////////////////////////////////////////////////////////// // // * initizlize //

// usage: // $(target).tchart() // // option: // ajaxParams: jquery ajax param // ajaxInterval: ajax polling interval [ Number (milliseconds) ] // onTaskClick: task click event callback [ function ] //

// * remove chart

//

// usage: // $(target).tchart(“remove”) // // * update chart

//

// usage: // $(target).tchart(“update”, source) // // source: // { // settings: { // drawActorsSummaryBarChart: boolean, // drawActorsSwimlaneChart: boolane, // drawTasksGanttChart: boolane, // drawTasksBarChart: boolane, // fontSize: Number, // width: Number, // actorsSwimlaneChart : { // barMaxHeight: Number // }, // tasksGanttChart : { // barMaxHeight: Number, // laneMaxHeight: Number // }, // tasksBarChart : { // barMaxHeight: Number, // }, // startTime: Number (millisecond) or null, // brushHeight: Number // }, // actors : { // actorId1 : { // name: string, // tasks : [ // taskId1 // ] // }, // actorId2 : { // name: string, // tasks : [ // taskId2 // ] // } // }, // tasks : { // task_Id1: { // name: string, // from: number (millisec time), // to: number (millisec time), // clickEventArg: object, // nextTasks : [ // taskId2 // ] // }, // task_Id2: { // name: string, // from: number (millisec time), // to: number (millisec time), // clickEventArg: object, // nextTasks : null // } // } // } // // * pending ajax polling

//

// usage: // $(target).tchart(“pendingAjax”) // // * resume ajax polling

//

// usage: // $(target).tchart(“resumeAjax”) //