contract UnitedfansToken is MintableToken {
    address public migrationMaster;
    address public migrationAgent;
    address public admin;
    address public crowdSaleAddress;
    uint256 public totalMigrated;
    string public name = "Goal Coin";
    string public symbol = "GC";
    uint256 public decimals = 18;
    bool public locked = true; // Lock the transfer of tokens during the crowdsale

    event Migrate(address indexed _from, address indexed _to, uint256 _value);

    event Locked();

    event Unlocked();

    modifier onlyUnlocked() {
        if (locked) 
            revert();
        _;
    }

    modifier onlyAuthorized() {
        if (msg.sender != owner && msg.sender != crowdSaleAddress && msg.sender != admin) 
            revert();
        _;
    }


    function UnitedfansToken(address _admin) public {
        // Lock the transfCrowdsaleer function during the crowdsale
        locked = true; // Lock the transfer of tokens during the crowdsale
        // transferOwnership(_admin);
        admin = _admin;
        crowdSaleAddress = msg.sender;
        migrationMaster = _admin;
    }

    function unlock() public onlyAuthorized {
        locked = false;
        Unlocked();
    }

    function lock() public onlyAuthorized {
        locked = true;
        Locked();
    }

    function transferFrom(address _from, address _to, uint256 _value) public onlyUnlocked returns (bool) {
        return super.transferFrom(_from, _to, _value);
    }

    function transfer(address _to, uint256 _value) public onlyUnlocked returns (bool) {
        return super.transfer(_to, _value);
    }



    // Token migration support:

    /// @notice Migrate tokens to the new token contract.
    /// @dev Required state: Operational Migration
    /// @param _value The amount of token to be migrated
    function migrate(uint256 _value) external {
        // Abort if not in Operational Migration state.
        
        if (migrationAgent == 0) 
            revert();
        
        // Validate input value.
        if (_value == 0) 
            revert();
        if (_value > balances[msg.sender]) 
            revert();

        balances[msg.sender] -= _value;
        totalSupply -= _value;
        totalMigrated += _value;
        MigrationAgent(migrationAgent).migrateFrom(msg.sender, _value);
        Migrate(msg.sender, migrationAgent, _value);
    }


    /// @notice Set address of migration target contract and enable migration
    /// process.
    /// @dev Required state: Operational Normal
    /// @dev State transition: -> Operational Migration
    /// @param _agent The address of the MigrationAgent contract
    function setMigrationAgent(address _agent) external onlyUnlocked() {
        // Abort if not in Operational Normal state.
        
        require(migrationAgent == 0);
        require(msg.sender == migrationMaster);
        migrationAgent = _agent;
    }

    function resetCrowdSaleAddress(address _newCrowdSaleAddress) external onlyAuthorized() {
        crowdSaleAddress = _newCrowdSaleAddress;
    }
    
    function setMigrationMaster(address _master) external {       
        require(msg.sender == migrationMaster);
        require(_master != 0);
        migrationMaster = _master;
    }
}
function setMigrationAgent(address _agent) external onlyUnlocked() {
        // Abort if not in Operational Normal state.
        
        require(migrationAgent == 0);
        require(msg.sender == migrationMaster);
        migrationAgent = _agent;
    }
/// @notice Set address of migration target contract and enable migration
/// process.
/// @dev Required state: Operational Normal
/// @dev State transition: -> Operational Migration
/// @param _agent The address of the MigrationAgent contract