public function paginate($collection, $options = array(), $dataRenderer = null)
    {
        $optRows = abs(intval(isset($options[self::OPTION_ROWS]) ? $options[self::OPTION_ROWS] : self::DEFAULT_ROWS));
        $optPage = abs(intval(isset($options[self::OPTION_PAGE]) ? $options[self::OPTION_PAGE] : self::DEFAULT_PAGE));
        $optFilter = isset($options[self::OPTION_FILTER]) ? $options[self::OPTION_FILTER] : null;

        if ($collection instanceof PaginatedStorage) {
            $amount = $collection->count($optFilter);
            $paginatedStorage = true;
        } else {
            $amount = count($collection);
            $paginatedStorage = false;
        }

        $rows = max(1, $optRows);
        $total = ceil($amount / $rows);
        $page = max(1, min($optPage, $total));
        $offset = ($page - 1) * $rows;

        $result = array(
            'offset' => $offset,
            'amount' => $amount,
            'total' => $total,
            'page' => $page,
            'rows' => $rows
        );

        if ($paginatedStorage) {
            $result['data'] = $collection->findPage($page, $rows, $optFilter);
        } else {
            $result['data'] = array_slice($collection, $offset, $rows);
        }

        if (is_callable($dataRenderer)) {
            $result['data'] = $dataRenderer($result['data']);
        }
        $result['length'] = count($result['data']);

        return $result;
    }