/**
	 * @param  TabTable   $tab       Current tab
	 * @param  UserTable  $user      Current user
	 * @param  int        $ui        1 front, 2 admin UI
	 * @param  array      $postdata  Raw unfiltred POST data
	 * @return string                HTML
	 */
	public function getCBpluginComponent( $tab, $user, $ui, $postdata )
	{
		global $_CB_framework;

		$format						=	$this->input( 'format', null, GetterInterface::STRING );
		$raw						=	( $format == 'raw' );

		if ( ! $raw ) {
			outputCbJs();
			outputCbTemplate();
		}

		$action						=	null;
		$function					=	null;
		$id							=	null;
		$viewer						=	CBuser::getMyUserDataInstance();
		$user						=	$viewer;
		$stream						=	null;
		$inline						=	false;
		$data						=	true;

		if ( isset( $postdata['stream'] ) && ( $postdata['stream'] instanceof StreamInterface ) ) {
			$stream					=	$postdata['stream'];

			if ( $stream instanceof ActivityInterface ) {
				$action				=	'activity';
				$function			=	'show';
			} elseif ( $stream instanceof CommentsInterface ) {
				$action				=	'comments';
				$function			=	'show';
			} elseif ( $stream instanceof TagsInterface ) {
				$action				=	'tags';
				$function			=	'show';
			}

			if ( isset( $postdata['inline'] ) ) {
				$inline				=	$postdata['inline'];
			}

			if ( isset( $postdata['data'] ) ) {
				$data				=	$postdata['data'];
			}

			$user					=	$stream->user();
		} else {
			$action					=	$this->input( 'action', null, GetterInterface::STRING );
			$function				=	$this->input( 'func', null, GetterInterface::STRING );

			if ( $action == 'recentactivity' ) {
				$action				=	'activity';
				$function			=	'recent';
			} elseif ( $action == 'myactivity' ) {
				$action				=	'activity';
				$function			=	'my';
			} elseif ( $action == 'hiddenactivity' ) {
				$action				=	'hidden';
				$function			=	'activity';
			} elseif ( $action == 'hiddencomments' ) {
				$action				=	'hidden';
				$function			=	'comments';
			}

			if ( ( $action == 'activity' ) || ( $function == 'activity' ) ) {
				$stream				=	new Activity();
			} elseif ( ( $action == 'comments' ) || ( $function == 'comments' ) ) {
				$stream				=	new Comments();
			} elseif ( ( $action == 'tags' ) || ( $function == 'tags' ) ) {
				$stream				=	new Tags();
			}

			if ( $stream && $raw ) {
				$token				=	$this->input( 'token', null, GetterInterface::STRING );

				$post				=	new Registry( base64_decode( $this->input( 'stream', null, GetterInterface::BASE64 ) ) );

				$source				=	$post->get( 'source', null, GetterInterface::STRING );
				$userId				=	$post->get( 'user', null, GetterInterface::INT );
				$direction			=	$post->get( 'direction', null, GetterInterface::INT );

				if ( $source !== null ) {
					$stream->source( $source );
				}

				if ( $userId !== null ) {
					$user			=	CBuser::getUserDataInstance( (int) $userId );

					$stream->user( $user );
				}

				if ( ! ( $stream instanceof TagsInterface ) ) {
					if ( $direction !== null ) {
						$stream->direction( $direction );
					}
				}

				$stream->load( $post );

				if ( ( $stream->token() != $token ) || ( ! $token ) ) {
					header( 'HTTP/1.0 401 Unauthorized' );
					exit();
				}

				$id					=	$stream->get( 'id', null, GetterInterface::INT );
			}
		}

		if ( $stream && ( ! ( ( $stream instanceof CommentsInterface ) || ( $stream instanceof TagsInterface ) ) ) ) {
			$hashtag				=	$this->input( 'hashtag', null, GetterInterface::STRING );

			if ( $hashtag !== null ) {
				$stream->set( 'filter', '#' . $hashtag );
			}
		}

		if ( ! $raw ) {
			ob_start();
		}

		switch ( $action ) {
			case 'comments':
				if ( ! $stream ) {
					if ( $raw ) {
						header( 'HTTP/1.0 401 Unauthorized' );
						exit();
					} else {
						cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
					}
				}

				switch ( $function ) {
					case 'new':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->saveComment( null, $stream, $user, $viewer );
						break;
					case 'save':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->saveComment( $id, $stream, $user, $viewer );
						break;
					case 'delete':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->deleteComment( $id, $stream, $user, $viewer );
						break;
					case 'hide':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->hideComment( $id, $stream, $user, $viewer );
						break;
					case 'unhide':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->unhideComment( $id, $stream, $user, $viewer );
						break;
					case 'load':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->showComments( $id, $stream, 3, true, $user, $viewer );
						break;
					case 'show':
					default:
						if ( isset( $postdata['stream'] ) && ( $postdata['stream'] instanceof CommentsInterface ) ) {
							$this->showComments( $id, $stream, ( $inline ? 2 : 0 ), $data, $user, $viewer );
						} else {
							$this->showComments( $id, $stream, ( $inline ? 2 : ( $raw ? 1 : 0 ) ), true, $user, $viewer );
						}
						break;
				}
				break;
			case 'activity':
				if ( ! $stream ) {
					if ( $raw ) {
						header( 'HTTP/1.0 401 Unauthorized' );
						exit();
					} else {
						cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
					}
				}

				switch ( $function ) {
					case 'new':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->saveActivity( null, $stream, $user, $viewer );
						break;
					case 'save':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->saveActivity( $id, $stream, $user, $viewer );
						break;
					case 'delete':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->deleteActivity( $id, $stream, $user, $viewer );
						break;
					case 'hide':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->hideActivity( $id, $stream, $user, $viewer );
						break;
					case 'unhide':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->unhideActivity( $id, $stream, $user, $viewer );
						break;
					case 'load':
						if ( ! $raw ) {
							cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
						}

						$this->showActivity( $id, $stream, 3, true, $user, $viewer );
						break;
					case 'recent':
						$stream->source( 'recent' );

						$menu				=	JFactory::getApplication()->getMenu()->getActive();

						if ( $menu && isset( $menu->id ) ) {
							CBActivity::loadStreamDefaults( $stream, $menu->params, 'activity_' );
						}

						$this->showActivity( $id, $stream, ( $raw ? 1 : 0 ), true, $user, $viewer );

						$_CB_framework->setMenuMeta();
						break;
					case 'my':
						$tab				=	new TabTable();

						$tab->load( array( 'pluginclass' => 'cbactivityTab' ) );

						if ( ! ( $tab->get( 'enabled' ) && CBActivity::canAccess( (int) $tab->get( 'viewaccesslevel' ), (int) $viewer->get( 'id' ) ) ) ) {
							if ( $raw ) {
								header( 'HTTP/1.0 401 Unauthorized' );
								exit();
							} else {
								cbRedirect( $_CB_framework->userProfileUrl( (int) $user->get( 'id' ), false, 'cbactivityTab' ), CBTxt::T( 'Not authorized.' ), 'error' );
							}
						}

						if ( ! ( $tab->params instanceof ParamsInterface ) ) {
							$tab->params	=	new Registry( $tab->params );
						}

						$stream->source( 'profile' );

						CBActivity::loadStreamDefaults( $activity, $tab->params, 'tab_activity_' );

						$this->showActivity( $id, $stream, ( $raw ? 1 : 0 ), true, $user, $viewer );

						$_CB_framework->setMenuMeta();
						break;
					case 'show':
					default:
						if ( isset( $postdata['stream'] ) && ( $postdata['stream'] instanceof ActivityInterface ) ) {
							$this->showActivity( $id, $stream, ( $inline ? 2 : 0 ), $data, $user, $viewer );
						} else {
							$this->showActivity( $id, $stream, ( $inline ? 2 : ( $raw ? 1 : 0 ) ), true, $user, $viewer );
						}
						break;
				}
				break;
			case 'hidden':
				if ( ! $stream ) {
					if ( $raw ) {
						header( 'HTTP/1.0 401 Unauthorized' );
						exit();
					} else {
						cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
					}
				}

				switch ( $function ) {
					case 'users':
						break;
					case 'types':
						break;
					case 'comments':
						$stream->source( 'hidden' );

						$stream->set( 'create_access', -1 );
						$stream->set( 'replies', 0 );

						$this->showComments( $id, $stream, ( $raw ? 1 : 0 ), true, $user, $viewer );
						break;
					case 'activity':
						$stream->source( 'hidden' );

						$stream->set( 'create_access', -1 );
						$stream->set( 'comments', 0 );

						$this->showActivity( $id, $stream, ( $raw ? 1 : 0 ), true, $user, $viewer );
						break;
				}

				$_CB_framework->setMenuMeta();
				break;
			case 'tags':
				if ( ! $stream ) {
					if ( $raw ) {
						header( 'HTTP/1.0 401 Unauthorized' );
						exit();
					} else {
						cbRedirect( 'index.php', CBTxt::T( 'Not authorized.' ), 'error' );
					}
				}

				switch ( $function ) {
					case 'show':
					default:
						if ( isset( $postdata['stream'] ) && ( $postdata['stream'] instanceof TagsInterface ) ) {
							$this->showTags( $id, $stream, ( $inline ? 2 : 0 ), $data, $user, $viewer );
						} else {
							$this->showTags( $id, $stream, ( $inline ? 2 : ( $raw ? 1 : 0 ) ), true, $user, $viewer );
						}
						break;
				}
				break;
			case 'cleanup':
				if ( ( ! $raw ) || ( $this->input( 'token', null, GetterInterface::STRING ) != md5( $_CB_framework->getCfg( 'secret' ) ) ) ) {
					header( 'HTTP/1.0 401 Unauthorized' );
					exit();
				}

				$this->cleanUp();
				break;
		}

		if ( ! $raw ) {
			$html						=	ob_get_contents();
			ob_end_clean();

			if ( ! $inline ) {
				$class					=	$this->params->get( 'general_class', null );

				$html					=	'<div id="cbActivity" class="cbActivity' . ( $class ? ' ' . htmlspecialchars( $class ) : null ) . '">'
										.		'<div id="cbActivityInner" class="cbActivityInner">'
										.			$html
										.		'</div>'
										.	'</div>';
			}

			echo $html;
		}
	}